Retour au Centre de connaissances
Identité

Historique de navigation injecté : session et global

Ce qui distingue l'historique injecté de la navigation par script, du dossier réutilisé et de history.pushState, et pourquoi history.length n'est pas l'historique global.

BotBrowser Team

Documentation

Vous préférez la doc produit maintenue ?

Cet article a une page équivalente dans le centre de documentation. Utilisez les docs pour le flux canonique, les flags à jour et la référence durable.

Une session de navigateur tout juste lancée a un passé très court. L'onglet ne contient qu'une seule entrée dans sa pile précédent et suivant, la barre d'adresse n'a rien à suggérer et la page d'historique peut être vide. Les équipes qui exécutent des tests de navigateur reproductibles veulent parfois partir d'un autre état : une session qui possède déjà une certaine profondeur de navigation, afin que le code testé rencontre les mêmes conditions à chaque exécution.

Cet objectif est facile à formuler et facile à mal résoudre, parce que deux enregistrements différents portent le nom d'historique. Ci-dessous, les deux enregistrements sont séparés, quatre façons de préparer une session sont comparées (la navigation par script, un dossier de données réutilisé, history.pushState et l'injection au lancement avec BotBrowser), les modes de --bot-inject-random-history sont listés, et une courte procédure montre comment vérifier le résultat sans confondre un enregistrement avec l'autre.

Deux panneaux : l'historique de session d'un onglet, lu par history.length, et l'historique global affiché dans chrome://history, avec le rappel de vérifier les deux.

Résumé

  • history.length compte les entrées de session d'un onglet ; il n'expose pas la liste du profil entier affichée par chrome://history.
  • La navigation par script crée les URL, redirections, cookies et données de stockage choisis. history.pushState() ne modifie que la pile de session de l'onglet courant.
  • --bot-inject-random-history=<count> fixe la profondeur de session au lancement pour vérifier une branche de façon reproductible, mais ne choisit ni les URL visitées ni l'état d'un site.

Sommaire de la guide

Deux historiques derrière un seul mot

Les navigateurs emploient le mot historique pour au moins deux enregistrements différents, et l'essentiel de la confusion autour de l'historique injecté vient du fait de les mélanger.

Le premier enregistrement est l'historique de session. Chaque onglet conserve une liste ordonnée des pages qu'il a affichées, et les boutons précédent et suivant parcourent cette liste. Les scripts de page y accèdent par l'interface History. Selon MDN, history.length est un entier en lecture seule qui contient le nombre d'entrées de l'historique de session, page actuellement chargée comprise, et une page ouverte dans un nouvel onglet renvoie 1. Appeler history.back(), history.forward() ou history.go() déplace le curseur dans la liste, tandis que history.pushState() et history.replaceState() la modifient sans charger de nouveau document.

Le second enregistrement est l'historique global. C'est la liste des adresses visitées à l'échelle du navigateur, qui alimente la page chrome://history et les suggestions de la barre d'adresse, que Chromium appelle l'omnibox. Il est conservé avec les données du profil, chaque onglet y contribue et un script de page ne peut pas le lire. Un nombre comme history.length ne dit rien de ce qu'il contient.

Les deux enregistrements répondent à des questions différentes. L'historique de session répond à la question du nombre d'étapes que cet onglet a derrière lui. L'historique global répond à la question des adresses que ce profil a visitées. Un test qui lit seulement history.length observe le premier enregistrement, et un test qui ouvre chrome://history observe le second. Aucune des deux observations ne prouve quoi que ce soit sur l'autre enregistrement : une technique qui ajoute une entrée à la pile précédent et suivant n'ajoute pas automatiquement une ligne à la page d'historique, et une technique qui remplit la page d'historique ne modifie pas automatiquement le nombre lu par un script.

Cela compte pour les tests, car le code des applications lit les deux types d'état, directement ou indirectement. Une application monopage peut n'afficher son propre bouton de retour que lorsque history.length dépasse 1. Un parcours de connexion peut décider où envoyer le visiteur selon qu'une entrée antérieure existe ou non. Une personne qui teste à la main voit des suggestions différentes dans la barre d'adresse dès que le profil a un peu de passé. Si un environnement de test démarre toujours avec le passé le plus court possible, le test n'exerce que la branche de première visite de ce code. L'injection vous donne un moyen d'exécuter l'autre branche volontairement.

Une autre propriété de l'historique de session est facile à oublier : il appartient à un seul onglet. Une fenêtre contextuelle, un deuxième onglet ou une fenêtre fraîchement ouverte démarrent leur propre liste. Lorsqu'un test lit history.length dans un onglet différent de celui qui a été préparé, il lit une autre liste, et la valeur 1 dans un nouvel onglet est le comportement attendu, pas le signe d'un échec de l'injection.

Quatre façons de préparer une session

Il existe quatre façons courantes de donner un peu d'historique à une session avant le début du vrai test. Elles diffèrent par l'enregistrement qu'elles touchent, par les effets de bord qu'elles provoquent et par leur reproductibilité.

La méthode la plus directe consiste à visiter des pages. Le script consigne l'URL HTTP, la cible finale de chaque redirection et history.length après chaque navigation, puis commence le vrai travail. C'est la seule méthode de la liste qui produit un état de page réel : les adresses visitées sont exactement celles que vous avez choisies, les redirections sont enregistrées telles que le site les a servies, et les cookies et le stockage sont remplis par les sites eux-mêmes. C'est aussi la méthode la plus coûteuse.

  • Temps. Chaque page doit se charger, de sorte que la préparation prend de quelques secondes à quelques minutes, selon les pages et la connexion.
  • Trafic réseau. Chaque visite envoie de vraies requêtes, consomme la bande passante de la route que le navigateur emprunte et peut se heurter à des limites de fréquence.
  • Effets de bord. Les pages exécutent leurs propres scripts, posent des cookies et envoient des événements d'analyse avant le début du test, qui ne part donc plus d'un état propre.
  • Variation. Les temps de chargement, les redirections et le contenu dynamique diffèrent d'une exécution à l'autre, si bien que l'historique obtenu n'est pas le même d'une fois sur l'autre.

Utilisez la navigation par script lorsque le test dépend d'adresses visitées précises ou d'un état de page réel. Rien d'autre dans cette liste ne peut fournir l'un ou l'autre.

Réutiliser un dossier de données utilisateur

Faire pointer chaque lancement vers le même --user-data-dir conserve ce que l'exécution précédente a stocké, y compris sa base d'historique global. Le prix à payer est que tout le reste est conservé aussi : cookies, stockage local, fichiers en cache et service workers. Vous ne pouvez pas reporter seulement l'historique et réinitialiser le reste.

Le test cesse aussi d'être strictement reproductible, car l'état de départ est ce que la dernière exécution a laissé. L'exécution N dépend alors des exécutions 1 à N-1. Copier le dossier depuis un instantané connu avant chaque exécution supprime la dérive, au prix d'une gestion de fichiers et d'espace disque. Cette approche convient aux tests qui portent réellement sur un état durable. C'est une manière lourde d'obtenir une profondeur d'historique.

Appeler history.pushState

Un script de page peut appeler history.pushState(state, '', url) pour ajouter une entrée à l'historique de session de l'onglet sans rien charger. MDN précise que la nouvelle URL doit avoir la même origine que l'URL actuelle, si bien qu'un script d'un site ne peut pas remplir la pile avec des adresses d'autres sites, et MDN ne décrit cet appel que par rapport à la pile de l'historique de session.

L'appel est une API de page conçue pour les applications monopage. Ce n'est pas un moyen de construire un historique de navigation. Dans un test, il sert à une seule chose : reproduire la façon dont une application monopage fait grandir sa propre pile précédent et suivant, afin de vérifier comment votre code réagit quand history.length augmente sans aucun chargement de page.

Injecter au lancement

L'option --bot-inject-random-history de BotBrowser (niveau PRO) emprunte une autre voie. Au lieu de visiter des pages, elle crée des entrées synthétiques au démarrage, avant le chargement de la première page. Comme les entrées sont générées au démarrage plutôt que chargées depuis des sites, la préparation ne demande aucun chargement de page scripté. Comme le nombre est piloté par l'option, deux lancements avec la même valeur partent de la même profondeur.

La documentation indique aussi clairement la portée : l'injection s'applique à chaque nouvelle session, et les entrées injectées ne persistent pas au-delà de la durée de vie de la session. Ce que l'option ne permet pas, c'est de choisir les adresses. Les entrées sont générées pour vous.

Modes de l'option d'injection

La documentation d'injection d'historique de BotBrowser présente deux façons d'activer l'option et une façon de la désactiver.

  • --bot-inject-random-history ou --bot-inject-random-history=true correspond au mode aléatoire. Il injecte un nombre aléatoire d'entrées de 2 à 7, ce qui, selon la documentation, donne un history.length de 3 à 8.
  • --bot-inject-random-history=15 correspond au mode exact. Il injecte exactement ce nombre d'entrées, de sorte que history.length vaut le nombre plus un : 15 entrées donnent 16 sur la première page. La documentation précise que la valeur doit être comprise entre 1 et 25.
  • --bot-inject-random-history=false désactive l'injection.

Le même réglage peut provenir de la configuration du profil par la clé injectRandomHistory, où true choisit le mode aléatoire et un nombre choisit le mode exact. Quand les deux sont présents, l'option en ligne de commande l'emporte sur le profil.

# Mode aléatoire : de 2 à 7 entrées
chromium-browser --bot-profile="path/to/profile.enc" --bot-inject-random-history
# Mode exact : 15 entrées, history.length vaut 16 sur la première page
chromium-browser --bot-profile="path/to/profile.enc" --bot-inject-random-history=15

Deux propriétés du mode exact comptent pour la reproductibilité. L'arithmétique est assez simple pour être vérifiée dans un test : la valeur attendue sur la première page est le nombre plus un. Et le mode aléatoire donne une plage, de sorte qu'une assertion doit accepter de 3 à 8 plutôt qu'un seul nombre. Si un test a besoin d'une valeur unique, utilisez le mode exact et écrivez le nombre dans la commande de lancement.

Comme les entrées sont générées et que la portée est la session, traitez chaque lancement comme une nouvelle injection. Ne vous attendez pas à ce que les entrées de l'exécution d'hier vous attendent dans un dossier de données réutilisé. Conservez plutôt la valeur de l'option dans la commande de lancement de chaque exécution, afin que la profondeur de départ soit consignée à côté du test.

L'option se combine avec les autres options d'injection de la documentation, comme --bot-cookies et --bot-bookmarks. Consultez Gestion des cookies et Injection de favoris pour celles-ci, et Gestion des profils pour garder des ensembles de profils organisés. Pour plusieurs contextes de navigateur au sein d'un même navigateur, la documentation présente l'historique par contexte comme une fonctionnalité ENT Tier3.

Choisir l'approche pour une exécution de test

Choisissez l'approche en fonction de la question que pose le test. Le tableau résume ce que touche chaque méthode et ce qu'elle coûte.

ApprocheCe qu'elle toucheRéseau et effets de bordReproductibilitéChoix des URL
Navigation par scriptHistorique de session et historique globalVraies requêtes, scripts de page, cookiesVarie selon les temps de chargement et le contenuOui
Dossier de données réutiliséTout ce qui a été enregistré avantAucune nouvelle requête, mais l'ancien état revientDépend des exécutions précédentesSeulement via les exécutions précédentes
history.pushStateHistorique de session d'un ongletAucunÉlevéeMême origine uniquement
Option d'injectionEntrées comptées par history.length, selon la documentationGénérées au démarrage, non chargées depuis des sitesÉlevée en mode exactNon

Le coût n'est qu'une partie de la décision. La reproductibilité en est l'autre, et c'est là que les méthodes diffèrent le plus. Une visite par script dépend des sites visités, un dossier réutilisé dépend des exécutions précédentes, et un nombre injecté ne dépend que de la commande de lancement. Quand il faut expliquer un échec de test un mois plus tard, une valeur unique dans une ligne de commande est bien plus facile à raisonner qu'un historique construit à partir de pages réelles. Quelques situations montrent comment le choix se traduit.

  • Vous avez besoin d'une pile précédent et suivant de profondeur connue. Utilisez le mode exact. Le history.length attendu est le nombre plus un, et la même commande de lancement donne chaque fois le même point de départ.
  • Vous avez besoin d'un peu de profondeur, mais pas d'un nombre précis. Utilisez le mode aléatoire et faites accepter aux assertions la plage de 3 à 8.
  • Vous avez besoin d'adresses précises ou d'un état de page réel. Utilisez la navigation par script. Une page qui lit un cookie posé par une visite antérieure, ou un site qui enregistre le nombre de visites, ne peut être préparé qu'en le visitant réellement.
  • Vous testez une transition de route d'une application monopage. Appelez history.pushState dans le test et vérifiez le gestionnaire popstate qui doit restaurer la vue précédente.
  • Vous avez besoin que tout l'état se reporte d'une exécution à l'autre. Réutilisez une copie du dossier de données et acceptez la dérive qui l'accompagne.

Les approches peuvent aussi se combiner. Un montage courant consiste à injecter une profondeur avec l'option, puis à scripter seulement les deux ou trois navigations dont le test dépend vraiment. La préparation reste courte et l'état des pages est réel là où cela compte. En les combinant, rappelez-vous que chaque navigation par script s'ajoute au compteur. Attendez-vous à ce que history.length augmente de un pour chaque nouvelle entrée en plus de la valeur injectée, et mesurez une base de référence dans votre propre build avant d'écrire des assertions exactes, car les redirections et les scripts de page peuvent ajouter des entrées que vous n'aviez pas prévues.

Vérifier ce qui s'est réellement passé

La vérification doit lire les deux enregistrements, car chacun dit quelque chose de différent. Une fiche d'exécution comportant les champs ci-dessous transforme une observation ponctuelle en quelque chose qu'un collègue peut reproduire.

  1. Lisez la valeur de session. Ouvrez une page et lisez history.length dans la console des outils de développement. En mode exact avec un nombre de 15, la première page renvoie 16, d'après la documentation. En mode aléatoire, la valeur doit se situer entre 3 et 8.
  2. Ouvrez chrome://history dans la même session et regardez les entrées. La documentation décrit l'effet sur history.length et sur la session. Elle ne décrit pas la page d'historique, donc la présence des entrées à cet endroit et leur forme sont à observer dans votre propre build et à noter, pas à supposer.
  3. Naviguez une fois et relisez la valeur. Elle doit augmenter de un pour la nouvelle entrée. Si ce n'est pas le cas, vérifiez si la page a redirigé ou remplacé sa propre entrée.
  4. Relancez avec les mêmes options et répétez les vérifications. Les entrées injectées s'appliquent à chaque nouvelle session, donc le mode exact doit donner les mêmes valeurs et le mode aléatoire doit rester dans sa plage.
  5. Notez la valeur de lancement à côté du résultat. Consignez l'option, le build, la longueur attendue, la longueur observée et ce que la page d'historique a affiché.

Écrivez les assertions sous forme de relations plutôt que de nombres magiques. En mode exact, la valeur attendue sur la première page est le nombre injecté plus un, et chaque navigation ultérieure du test en ajoute une. Exprimer la vérification ainsi la maintient correcte quand quelqu'un change le nombre injecté, et un échec pointe alors vers une différence précise entre valeur attendue et valeur observée. En mode aléatoire, n'affirmez que la plage documentée et notez la valeur observée, afin qu'une exécution surprenante puisse encore être comprise ensuite.

La plupart des vérifications ratées viennent d'une courte liste d'erreurs. La première est de lire history.length dans un onglet différent de celui qui a été préparé, où un nouvel onglet renvoie correctement 1. La deuxième est de comparer une valeur injectée à un nombre mesuré après des navigations supplémentaires. La troisième est d'attendre que les entrées survivent à un redémarrage, ce que la documentation dit ne pas être le cas. La quatrième est d'écrire une assertion exacte face au mode aléatoire.

Si history.length reste à 1, la documentation désigne trois causes. L'option a peut-être été passée en dehors du tableau d'arguments du lanceur. La licence n'est peut-être pas active, auquel cas la sortie console de BotBrowser signale une erreur de licence. Ou le nombre a été écrit sans le signe égal, ou en dehors de la plage autorisée de 1 à 25.

Un history.length conforme montre seulement que la session porte des entrées. Il ne montre pas comment un site donné traitera la session, et aucune affirmation de ce genre n'est faite ici. L'historique injecté est une entrée parmi d'autres d'une session de test, à côté des cookies, des favoris, de la langue et du fuseau horaire que vous configurez séparément.

Un relevé par exécution, et ce qu'un diff signifie

Champ du relevéÀ quoi il sert
flagLa valeur exacte de --bot-inject-random-history, ou exact
buildLa chaîne de compilation du navigateur utilisée
firstPageLengthhistory.length sur la première page, avant navigation
afterOneNavigationLa même valeur après exactement une navigation
historyPageSi chrome://history listait des entrées, et sous quelle forme

Cinq champs suffisent à distinguer un vrai changement d'une exécution mal lue, mais seulement si les cinq sont écrits à chaque fois. Un relevé qui porte la longueur sans la compilation ne peut pas distinguer « la graine a changé » de « le navigateur a changé », et c'est cette ambiguïté qui rend un rapport de régression inexploitable.

Lisez le relevé en comparant deux exécutions champ par champ, et non deux nombres isolés. Quand seul build diffère et que firstPageLength le suit, la graine s'est bien appliquée et la compilation a déplacé le décalage. Quand seul flag diffère, le décalage doit se déplacer exactement de la différence du compte injecté si les deux exécutions utilisent un compte exact. Quand firstPageLength ne change pas entre deux comptes exacts différents, l'option n'a pas atteint le processus et le reste du relevé décrit deux fois le même lancement ; deux exécutions en mode aléatoire peuvent légitimement tomber sur la même longueur dans la plage documentée, donc une valeur inchangée ici ne prouve rien.

Le champ de navigation est celui qui attrape un décalage d'un. Une première page annonce le compte injecté plus un, donc un relevé dont afterOneNavigation égale firstPageLength décrit une navigation qui ne s'est jamais validée, généralement parce que la page a redirigé ou remplacé sa propre entrée. C'est un constat sur le site, pas sur la graine.

Laissez historyPage comme observation et non comme assertion. La documentation ne décrit pas ce que la page d'historique affiche pour les entrées injectées : notez donc ce que vous avez vu avec la compilation et laissez la personne suivante comparer. Un relevé qui affirmerait un état attendu encoderait une promesse que la documentation n'a jamais faite.

Conclusion pratique

Où BotBrowser s'insère et où il s'arrête. L'historique injecté n'est qu'une petite partie d'un plan de test. Il fixe une variable, la profondeur de la session au lancement, afin que les autres variables puissent être étudiées sur un fond stable.

BotBrowser (PRO) prend en charge l'injection d'un historique de navigation synthétique au lancement via --bot-inject-random-history, soit avec un nombre aléatoire d'entrées, soit avec un nombre exact, afin que vous puissiez démarrer chaque session de test avec une profondeur d'historique reproductible sans chargement de pages par script. Il ne vous permet pas de choisir les URL injectées, ne peut pas garantir que les entrées correspondent à une langue ni qu'elles ressemblent à un usage réel pour un site donné, et ne remplace pas la navigation par script lorsque des URL visitées précises ou un état de page réel sont nécessaires.

Consultez la documentation actuelle pour le niveau, la plage de nombres et la formulation sur history.length avant de vous y fier dans une version de production, et utilisez la page MDN sur history.length comme référence pour la partie session du comportement.

Sources publiques

#History#Injection#Identity#Browsing#confidentialité

Cet article fait partie du guide : Surfaces d’identité du navigateur : vue de cohérence pratique

Faites passer BotBrowser de la recherche à la production

Utilisez ces guides pour comprendre le modèle, puis passez à la validation multi-plateforme, aux contextes isolés et au déploiement navigateur prêt pour l'échelle.