6
votes

Impossible de comparer les énumérations en jasmin après la migration angulaire de 6 à 7

Je suis en train de migrer une application Angular de la v6 vers la v7. Tout va bien sauf tout test qui compare les énumérations. Lorsque j'exécute mes tests, j'obtiens de nombreuses erreurs concernant mes énumérations comme suit

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/spec",
    "module": "commonjs",
    "target": "es5",
    "baseUrl": "",
    "types": [
      "jasmine",
      "node"
    ]
  },
  "files": [
    "test.ts",
    "polyfills.ts"
  ],
  "include": [
    "**/*.spec.ts",
    "**/*.d.ts"
  ]
}

Voici un exemple de test en cours d'exécution:

{
  "compileOnSave": false,
  "compilerOptions": {
    "importHelpers": true,
    "preserveConstEnums": true,
    "outDir": "./dist/out-tsc",
    "baseUrl": "src",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "noUnusedLocals": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2016",
      "dom"
    ]
  }
}

Cependant, si je transforme mon énumération en nombre, mes tests fonctionnent parfaitement! Ce serait loin d'être idéal pour mettre à jour mes spécifications partout comme ceci:

"dependencies": {
    "@angular/animations": "~7.2.0",
    "@angular/common": "~7.2.0",
    "@angular/compiler": "~7.2.0",
    "@angular/core": "~7.2.0",
    "@angular/forms": "~7.2.0",
    "@angular/http": "~7.2.0",
    "@angular/platform-browser": "~7.2.0",
    "@angular/platform-browser-dynamic": "~7.2.0",
    "@angular/router": "~7.2.0",
    "core-js": "^2.5.4",
    "rxjs": "~6.4.0",
    "tslib": "^1.9.0",
    "zone.js": "~0.8.26",
    "@angular/cdk": "^7.0.3",
    "@angular/flex-layout": "7.0.0-beta.24",
    "@angular/material": "7.3.6",
    "hammerjs": "2.0.8",
    "intl": "1.2.5",
    "jshashes": "1.0.7",
    "lodash-es": "4.17.11",
    "request-promise-native": "1.0.5",
    "stream": "0.0.2",
    "timers": "0.1.1",
    "url-search-params-polyfill": "5.0.0",
    "xml2js": "0.4.19"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.13.0",
    "@angular/cli": "~7.3.7",
    "@angular/compiler-cli": "~7.2.0",
    "@angular/language-service": "~7.2.0",
    "@types/node": "~8.9.4",
    "@types/jasmine": "~2.8.8",
    "@types/jasminewd2": "~2.0.3",
    "codelyzer": "~4.5.0",
    "jasmine-core": "~2.99.1",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~4.0.0",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "~2.0.1",
    "karma-jasmine": "~1.1.2",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.4.0",
    "ts-node": "~7.0.0",
    "tslint": "~5.11.0",
    "typescript": "~3.2.2",
    "@types/lodash-es": "4.17.1",
    "gulp": "3.9.1",
    "gulp-stylelint": "7.0.0",
    "jasmine-data-provider": "2.2.0",
    "karma-cli": "1.0.1",
    "karma-junit-reporter": "1.2.0",
    "karma-parallel": "0.3.0",
    "karma-spec-reporter": "0.0.32",
    "lodash": "4.17.11",
    "moment": "2.22.2",
    "npm": "6.0.0",
    "protractor-beautiful-reporter": "1.2.5",
    "protractor-jasmine2-screenshot-reporter": "0.5.0",
    "stylelint": "9.6.0",
    "stylelint-order": "1.0.0",
    "tslint-jasmine-noSkipOrFocus": "1.0.9"
  }

Je ne sais pas si j'ai manqué quelque chose dans mon package.json . J'ai comparé un nouveau projet angular 7 à mes propres projets et les versions de angular core, dactylographié, jasmin et karma entre eux sont les mêmes.

Comment puis-je obtenir mes tests pour comparer correctement les énumérations? Voici mon package.json

expect(component.selectedPlanDuration).toBe(<number> PlanDuration.SixMonths);

tsconfig.json:

export enum PlanDuration {
  SixMonths,
  TwelveMonths
}

...
    it('should toggle plan duration to six months if the event source id is the toggle duration and the event is not checked', () => {

      component.selectedPlanDuration = PlanDuration.TwelveMonths;
      component.handleToggle(event);
      expect(component.selectedPlanDuration).toBe(PlanDuration.SixMonths); // Tests cannot run because of errors here
    });

tsconfig.spec .json

ERROR in src/.../some-thing.component.spec.ts: error TS2345: Argument of type 'PlanDuration.SixMonths' is not assignable to parameter of type 'Expected<PlanDuration.TwelveMonths>'.


5 commentaires

Essayez plutôt "export const enum ...", et dans votre TSConfig, essayez de définir preserveConstEnums: true . Les énumérations sont en fait des nombres sauf indication contraire, et n'ont pas besoin de transtypage, mais Typescript compile funky avec les énumérations que j'ai trouvées


@JonathanSchmold, pouvez-vous poster ceci comme réponse? Je peux essayer votre suggestion lundi matin et si cela fonctionne, je vous décernerai volontiers cette prime.


Je peux certainement :)


Je suppose que cela pourrait être un problème avec Karma et Jasmine. J'en ai vu et j'ai dû passer de la 4e version à la 3.99


C'est un bug dans la définition de type de jasmin. Vérifiez ma réponse pour plus de détails et comment y remédier.


3 Réponses :


2
votes

J'ai rencontré des problèmes il y a quelque temps où Angular me disait qu'il ne pouvait pas accéder à MyEnumValue of undefined . Après quelques manipulations, j'ai trouvé que l'exportation de toutes les énumérations en tant que const et l'ajout de "preserveConstEnums": true à mon tsconfig.json le permettaient très bien.

Mais les énumérations sont toujours des nombres, sauf indication contraire, et heureusement n'ont pas besoin de cast, mais la compilation d'énumérations de Typescript peut parfois être funky de la même manière que les interfaces le sont.

Edit:

In votre composant, assurez-vous que:

// If you give this a default value, TypeScript will assume
// that the only "valid" type is PlanDuration.TwelveMonths
// Type evaluates to: PlanDuration | number between 0 and 1;
selectedPlanDuration: PlanDuration = PlanDuration.TwelveMonths;

// Type evaluates to: PlanDuration.TwelveMonths | 1;
selectedPlanDuration = PlanDuration.TwelveMonths


8 commentaires

J'ai essayé votre suggestion, ainsi que la correspondance d'un tsconfig entre une application vanilla ng7 et notre application de production, et je n'ai pas pu faire fonctionner cela. Je pense cependant que c'est un problème avec TS et je continuerai d'enquêter.


essayez expect (component.selectedPlanDuration.valueOf ())


Hé en fait, quel type d'annotation avez-vous donné au composant? J'ai l'impression que vous l'avez défini comme quelque chose de funky, et que le type attribué à selectedPlanDuration est littéralement PlanDuration.TwelveMonths . Typescript vous permet d'affecter un «type» à une variable sous la forme d'une valeur unique d'un seul type. soit q: 3 = 4; // erreur


J'ai mis à jour ma réponse pour couvrir quelque chose qui pourrait être le problème, mais qui n'a pas été fourni dans votre question. C'est probablement le problème


Mon composant a ce membre: public selectedPlanDuration: PlanDuration = PlanDuration.SixMonths; . La suggestion de valueOf fonctionne bien, cependant, pas idéale pour corriger de nombreuses spécifications pour contenir cette méthode.


Pouvez-vous publier votre fichier tsconfig complet?


@JonathanScmold, j'ai posté mon tsconfig dans ma question maintenant


continuons cette discussion en chat .



0
votes

TL;DR

Solution rapide: accédez à node_modules/@types/jasmine/index.d.ts , recherchez type Expected code>

// jasmine/index.d.ts
declare namespace jasmine {
  interface Matchers<T> {
    toBe(expected: Expected<T>, expectationFailOutput?: any): boolean;

Voilà :)


Pour plus de détails, lisez la suite:

Je crois que c'est un bug dans la définition des types de jasmine. J'ai mis en place un nouvel espace de travail ng7 et j'essaye de reproduire votre problème. Voici ma conclusion:

Il y a deux fichiers .d.ts liés au jasmin dans l'espace de travail:

// jasminewd2/index.d.ts
declare namespace jasmine {
  interface Matchers<T> {
    toBe(expected: any, expectationFailOutput?: any): Promise<void>;
    ...

Je suis Je ne sais pas à 100% comment ces deux éléments fonctionnent ensemble, mais ils déclarent des types conflictuels pour les mêmes utils jasmine. Par exemple:

// package.json
  ...
  "@types/jasmine": "~2.8.8",
  "@types/jasminewd2": "~2.0.3",
// Change this line:
// type Expected<T> = T | ObjectContaining<T> | Any | Spy;
// to:
type Expected<T> = any;

Le problème est maintenant dans jasmine / index.d.ts .

Cette ligne toBe (attendu: attendu ) est tout simplement FAUX. Ceci est un cas de test, vous êtes certainement autorisé à tester par rapport à n'importe quelle valeur. Pourtant, Expected est déclaré comme un type complexe sans point.

Le moyen le plus simple de le corriger est de le corriger manuellement. La solution est déjà donnée au début. Bravo.


3 commentaires

Une note latérale. Personnellement, je pense que ts-check un fichier source de cas de test au moment de la compilation est une exagération et devrait être désactivé pour de bon. Le contrôle Ts à l'heure de départ est bien cependant.


Cette solution rapide a du sens, mais comment cela fonctionnerait-il dans une configuration de serveur de production? Peut-être qu'une meilleure option (autre que la soumission d'un PR) est de remplacer cette définition de type et de l'utiliser dans les tests. Bien que cela nécessiterait toujours un changement dans chaque fichier qui compare les énumérations et que l'OP ne veut pas faire cela.


@Nanotron La fusion de déclarations devrait aider. Je n'ai pas d'ordinateur autour de moi, je ne peux donc pas le tester, mais je suppose que cela devrait fonctionner: ajoutez un patchJasmine.d.ts quelque part qui est inclus dans tsconfig.json , puis dans le fichier vous ajoutez ceci: declare namespace jasmine {type Attendu = any; } .



-1
votes

J'ai rencontré le même problème lors de l'implémentation de nouveaux tests dans un projet Angular 7 (sans migration de 6 à 7). Si vous préférez une solution de contournement plutôt qu'une modification susceptible d'affecter les futures mises à jour de Karma / Jasmine, vous pouvez permuter les comparaisons afin que l'énumération soit la première:

expect(PlanDuration.SixMonths).toBe(component.selectedPlanDuration);


1 commentaires

Je ne sais pas pourquoi cela a été voté, mais je suis arrivé ici en cherchant pourquoi les Enums de mes tests où des erreurs et cette méthode étaient les plus plausibles pour moi (et j'imagine que la plupart des gens qui rencontrent ce message) mettre en place.