28 votes

est-il possible de vider et de restaurer window.angular pour créer un instantané récupérable ?

Mon application nécessite des étapes complexes au sein de l'UX pour atteindre certains de ses nombreux états. Cela rend le cycle de développement et de test extrêmement lourd pour les simples modifications de la mise en page qui doivent être vérifiées visuellement pour un large éventail d'états.

Je cherche donc à savoir s'il est possible de faire un dump/snapshot de l'application en cours d'exécution (c'est-à-dire window.angular, ou peut-être $rootscope) de telle sorte que je puisse rapidement restaurer à partir de ce snapshot, lancer un $rootscope.$digest() et voilà.

Avez-vous des suggestions sur la manière d'y parvenir ?

Je ne cherche pas à ce qu'un instantané restauré soit fonctionnel, c'est-à-dire qu'il n'est pas nécessaire qu'il y ait des observateurs actifs ou des abonnements de diffusion. Il faut juste qu'il rende fidèlement une vue pour une inspection visuelle.

--edit--

Je commence à penser que ça ne peut pas être fait.

Ce que j'ai réalisé, c'est que tous mes projets Angular auront désormais un seul service appelé VmStateService et, fondamentalement, chaque élément de données VM qui affecte la vue affichée. doit vivent dans ce service unique, qui est injecté dans chaque contrôleur. De cette façon, je n'ai qu'un seul objet propre (il n'a pas de fonctions), que je peux vider dans une chaîne de caractères, ou enregistrer dans un stockage local, et restaurer pour créer n'importe quelle vue que je veux tester.

Je suppose qu'il est regrettable que tout le monde apprenne AngularJS en faisant $scope.foo = "bar", puis passe le reste de sa carrière à se rendre compte du désordre que cela crée.

2voto

dnozay Points 3672

Si vous faites vos tests avec karma alors vous pouvez utiliser karma-fixtures-preprocessor .

L'essentiel :

  1. créer un service qui renvoie un objet fictif ou créer des montages de test
  2. en utilisant injection de dépendances (angular pour la victoire) ; injectez vos données fantaisie / fantaisie et testez votre logique de manière isolée.

Si vous avez des problèmes avec cette approche, alors vous avez très probablement faible séparation des préoccupations .

Consultez ces excellentes ressources :

mon analyse de $0.02

Mon application nécessite des étapes complexes au sein de l'UX pour atteindre certains de ses nombreux états. Cela rend le cycle de développement/test extrêmement lourd pour les simples modifications de la mise en page qui doivent être vérifiées visuellement pour un large éventail d'états.

Cela ressemble beaucoup à une faible séparation des préoccupations. Si on vous donne toutes les données, il devrait être facile de déclencher une vue ou de passer à un état.

Je cherche donc à savoir s'il est possible de faire un dump/snapshot de l'application en cours d'exécution (c'est-à-dire window.angular, ou peut-être $rootscope) de telle sorte que je puisse rapidement restaurer à partir de ce snapshot, lancer un $rootscope.$digest() et voilà.

Cela ressemble beaucoup à l'utilisation d'appareils. Pour ce qui est des données que vous devez enregistrer, l'utilisation de intercepteurs http pour enregistrer le contenu pourrait vous convenir (ne le faites pas dans la production). Vous pourriez ensuite utiliser le contenu que vous venez d'enregistrer pour l'utiliser dans vos données factices.

tester une vue avec différentes entrées

Cela signifie généralement que vous souhaitez tester des directives personnalisées avec des données différentes. Vous pouvez le faire avec :

  • autant de montages que nécessaire pour chaque cas d'essai,
  • beforeEach pour charger les données appropriées pour un groupe de cas d'essai,
  • en utilisant $digest() pour mettre à jour la vue,
  • vérifier le balisage mis à jour avec .find() o .attr() etc, sur l'élément.
  • vérifier le rendu avec .clientHeight , .clientWidth etc.

valider (visuellement) de nombreux éléments d'interface utilisateur différents

Il y a beaucoup de choses que vous pouvez faire pour vérifier manuellement les éléments.

Ajout d'une "page de test", où les mêmes éléments sont affichés avec des données, des classes, des styles, etc. différents. Lorsque certaines des données sont fournies par l'utilisateur et qu'il est difficile de les vérifier de manière automatisée, cette approche peut s'avérer utile. Voici quelques exemples : Bootswatch qui vous permet de vérifier de nombreux éléments de l'interface utilisateur de bootstrap sous différents thèmes. jquery UI ThemeRoller qui vous permet de vérifier rapidement de nombreux éléments sous différents thèmes.

fonctionnalité de vidage / restauration

Cette question contient de bons points sur l'accès aux scopes enfants à partir du scope parent : AngularJS - Accès à la portée enfant

Points supplémentaires :

  • vous devez savoir ce qu'est le balisage avant qu'il ne soit mis à jour,
  • Le dumping peut être facile si vous parvenez à obtenir des données de tous les scopes nécessaires,
  • Cependant, la restauration peut ne pas fonctionner du tout en raison de la façon dont vous effectuez les mises à jour. Par exemple, le fait de faire un élément à la fois peut déclencher des mises à jour, le fait de ne pas le faire dans le bon ordre peut déclencher des mises à jour qui peuvent modifier les éléments, etc.

Cela devient très poilu. Je ne connais pas de bibliothèque qui fournisse une fonctionnalité générique de vidage/restauration.

1voto

Compynerd255 Points 436

Le problème avec la simple utilisation de JSON.Stringify c'est qu'il ne capturera pas les fonctions correctement, ni les fonctions légitimes. undefined ou des références circulaires. Vous pouvez utiliser comme point de départ l'outil Node JS util.inspect() :

https://github.com/nodejs/node/blob/master/lib/util.js#L87

Celui-ci fait déjà la moitié du travail - lire un objet, le formater correctement, gérer toutes les nuances. Il lit également les fonctions et les références circulaires. Vous devez faire l'autre moitié du travail en le retraduisant, mais vous devriez y arriver.

(Et ce sont les termes de la licence de Node - licence MIT pour Node lui-même, d'autres bibliothèques peuvent être légèrement plus strictes (mais pas tant que ça)) :

https://raw.githubusercontent.com/nodejs/node/master/LICENSE

1voto

Bryan Rayner Points 712

Modifier

Tout d'abord, si tout ce qui vous intéresse est d'obtenir une vue pour une inspection visuelle, pourquoi ne pas le faire ?

document.body.parentNode.innerHTML

Mais, vous voulez probablement plus que cela, surtout si vous voulez capturer la valeur des champs de saisie, etc., des choses qui ne sont pas représentées par le HTML statique du DOM.

Pour résoudre votre problème, vous devez capturer toutes les informations dont vous avez besoin pour recréer l'état de votre vue. En Angular, cela signifie probablement :

  • L'URL actuelle
  • Toute valeur sur $rootScope
  • L'état interne de tous les services qui fournissent des données à votre couche d'affichage.

Cela est difficile à faire, à moins de planifier l'architecture de votre application autour de cette fonctionnalité. Quelle que soit la façon dont vous le découpez, vous devrez procéder à un remaniement. Vous aurez également besoin d'une architecture qui encourage un état que vous pouvez instantanéiser, de sorte que le développement futur puisse également être sauvegardé/restauré.

Il semble que vous pourriez bénéficier de l'architecture FLUX. Si vous n'êtes pas familier avec FLUX, je vous recommande de regarder sur le site web du flux .

J'ai implémenté une version de FLUX dans mon application Enterprise Angular, en utilisant RxJS pour les actions, et des services pour les magasins (je les nomme simplement <Feature>Store et ils sont injectés via module.service('<Feature>Store', /*Definition*/) ).

Cependant, il existe une implémentation de Flux qui pourrait résoudre ce que vous recherchez, https://github.com/rackt/redux . Redux est construit autour de React, il faudrait donc construire un pont entre la couche d'état de l'application et la vue (qui pourrait être contrôlée par Angular).

Redux conserve l'état de l'application dans un seul objet JS, et suit chaque changement atomique de cet objet. Vous seriez en mesure d'obtenir une sauvegarde/un chargement instantané de l'état de l'application, en théorie.

0voto

floribon Points 1149

Voici une tentative naïve.

Uso:

  • serialize($rootScope) pour obtenir une chaîne de caractères, une version sérialisée de l'étendue Root et des enfants que vous enregistrerez dans un fichier, un localStorage, etc.

  • restore(myCopy, $rootScope) pour tout remettre dans le $rootScope. myCopy est la chaîne, version sérialisée renvoyée par la méthode copy plus tôt.

Seules les propriétés personnalisées (et non les fonctions) sont sérialisées. Tout ce qui commence par un signe de dollar est considéré comme privé pour Angular et ne doit pas être manipulé. S'il vous arrive d'avoir des propriétés personnalisées qui commencent par le signe $ vous pouvez ajuster la fonction afin de n'ignorer que celle qui est privée à angular.


function serialize(target, source) {
  source = source || {};
  for (var key in target) {
    if (!target.hasOwnProperty(key)) { continue; }
    if (key[0] === '$' || key === 'constructor') continue;

    if (typeof target[key] !== 'function') {
      try {
        source[key] = JSON.stringify( target[key] );
      } catch(e) {}
    }
  }

  if (target.$$nextSibling) {
    source.$$nextSibling = {};
    serialize(target.$$nextSibling, source.$$nextSibling);
  }

  if (target.$$childHead) {
    source.$$childHead = {};
    serialize(target.$$childHead, source.$$childHead);
  }

  return JSON.stringify(source);
}

function restore(copy, $rootScope) {
  try {
    copy = JSON.parse(copy);
  } catch(e) {}

  for (var key in copy) {
    if (!copy.hasOwnProperty(key)) { continue; }

    try {
      $rootScope[key] = JSON.parse(copy[key]);
    } catch(e) {
      $rootScope[key] = copy[key];
    }
  }

  if (copy.$$nextSibling) {
    $rootScope.$$nextSibling = $rootScope.$$nextSibling || {};
    restore(copy.$$nextSibling, $rootScope.$$nextSibling);
  }

  if (copy.$$childHead) {
    $rootScope.$$childHead = $rootScope.$$childHead || {};
    restore(copy.$$childHead, $rootScope.$$childHead);
  }
}

// Create a $rootScope serialized copy that can be stored in local storage, etc
var copy = serialize($rootScope);

// Restore a serialized copy into $rootScope
restore(copy, $rootScope);

0voto

Je vois que mon petit projet pourrait satisfaire partiellement vos exigences.

https://github.com/vorachet/angular-state-manager

Il est encore jeune et l'objectif de conception est d'être un outil de maintenance pour aider à la compréhension des applications Angular. Je serais heureux d'étudier vos besoins détaillés et d'essayer de poursuivre le développement pour résoudre votre problème.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X