<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Jérémy Chauvin</title>
    <description>The latest articles on Forem by Jérémy Chauvin (@singebob).</description>
    <link>https://forem.com/singebob</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F294107%2Fc263cfe2-08da-47b2-96d0-09861b5b6e06.png</url>
      <title>Forem: Jérémy Chauvin</title>
      <link>https://forem.com/singebob</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/singebob"/>
    <language>en</language>
    <item>
      <title>Git hooks: not everything is worth blocking for</title>
      <dc:creator>Jérémy Chauvin</dc:creator>
      <pubDate>Thu, 30 Apr 2026 21:09:22 +0000</pubDate>
      <link>https://forem.com/singebob/git-hooks-not-everything-is-worth-blocking-for-361f</link>
      <guid>https://forem.com/singebob/git-hooks-not-everything-is-worth-blocking-for-361f</guid>
      <description>&lt;p&gt;Git hooks are a practice we see more and more in projects. We often adopt them because we've seen them elsewhere, or because they seem like a good idea to ensure code quality. But is that really the case?&lt;/p&gt;

&lt;p&gt;Before going further, let's explain what a git hook is. With git, you can run scripts when you want to create a commit, push, etc. (pre-commit, pre-push, etc.).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;a href="https://github.com/typicode/husky" rel="noopener noreferrer"&gt;Husky&lt;/a&gt; is a great tool to discover and create your first hooks&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By using a pre-commit hook, when you run the "git commit" command, a script is executed. If it fails, the commit is cancelled. You're then forced to fix the problem before you can commit.&lt;/p&gt;

&lt;p&gt;To make collaboration easier within the team, you might think "Great, I'll be able to check that":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;all my tests pass&lt;/li&gt;
&lt;li&gt;my linter passes&lt;/li&gt;
&lt;li&gt;my formatter passes&lt;/li&gt;
&lt;li&gt;my commit name follows conventions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's where the problems start. Because yes, the feedback will be faster, but at what cost?&lt;/p&gt;

&lt;h2&gt;
  
  
  A commit is not a delivery
&lt;/h2&gt;

&lt;p&gt;With hooks, we run tests, the linter, the formatter, and commit name validation every time we want to commit. Making a commit becomes slow and frustrating. We're in our flow, we've made progress on our feature, and we have to wait for everything to pass before we can share our work.&lt;/p&gt;

&lt;p&gt;And what happens in the end? If we end up bypassing hooks with &lt;code&gt;--no-verify&lt;/code&gt;, it's to get back to a fast dev flow.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Git has a &lt;a href="https://git-scm.com/docs/githooks#_pre_commit" rel="noopener noreferrer"&gt;&lt;code&gt;--no-verify&lt;/code&gt;&lt;/a&gt; option on its commands to skip hooks&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The other problem is that hooks push us toward "perfect" code at every commit. But a commit is not a delivery. Let's take a concrete example: we're working in TDD, we've just written a red test that describes the behavior we want to implement. We want to commit this test before moving on to the implementation. Except the pre-commit hook runs the build or the linter or the type check, it fails, and the commit is blocked. We're forced to either implement right away or use &lt;code&gt;--no-verify&lt;/code&gt;. The red-green-refactor cycle, which relies precisely on intermediate states, becomes painful.&lt;/p&gt;

&lt;p&gt;That's the whole point of a commit: saving a state so we can go back if needed. With overly strict hooks, we're asked for perfect code at every save. We lose that freedom.&lt;/p&gt;

&lt;p&gt;And the problem doesn't stop at the commit. Even when the pre-commit hook is limited to lint and build, we often find tests in a pre-push hook. Result: we can commit locally, but can't push until the tests pass. If we're doing pair or mob programming and want to share a work-in-progress state, it's blocked. If we need a colleague's opinion on an approach before continuing, it's blocked. We fall back into the same logic: "perfect" code just to be able to collaborate.&lt;/p&gt;

&lt;p&gt;And that's not the only problem...&lt;/p&gt;

&lt;h2&gt;
  
  
  Double pain, zero gain
&lt;/h2&gt;

&lt;p&gt;The other issue we create with hooks is duplication. The same checks run locally via hooks, then a second time in the pipeline (GitHub Actions, GitLab CI, etc.). We wait for the hooks to pass, then wait for CI to run the exact same thing. We don't save time, we lose it.&lt;/p&gt;

&lt;p&gt;And it's not just a matter of time. We end up maintaining checks in two places: the hook config and the pipeline. We update an option in a command on the CI side but forget to do it on the hook side, or vice versa. The two diverge, and we only notice when something breaks.&lt;/p&gt;

&lt;p&gt;On top of that, we risk falling into the "it works on my machine" trap, or the exact opposite. The local environment and CI are not the same thing. Tool versions, dependencies, config... there are many reasons the result could be different. We add cognitive load trying to understand why it passes locally but fails in the pipeline, or vice versa.&lt;/p&gt;

&lt;p&gt;Ultimately, it's the CI that decides whether we can merge or not. It's the source of truth. If we trust it to block a merge, why duplicate that work locally?&lt;/p&gt;

&lt;p&gt;But then, if hooks cause so many problems, why do we keep using them?&lt;/p&gt;

&lt;h2&gt;
  
  
  What we're really compensating for
&lt;/h2&gt;

&lt;p&gt;The real problem is our CI's feedback loop. The pipeline takes 20 minutes, we don't get any notification on failure, and most importantly, everything stays very opaque. Because we have one big step that mixes a bunch of things, and to find out what broke we have to dig through logs. It's frustrating.&lt;/p&gt;

&lt;p&gt;Hooks are a response to that frustration. We want faster, clearer feedback, closer to us. And that makes sense.&lt;/p&gt;

&lt;p&gt;In any case, hooks are a band-aid, not a solution. We're treating the symptom but not the cause. The real question isn't "how to get faster feedback locally", it's "why is my feedback slow and unclear in the first place".&lt;/p&gt;

&lt;p&gt;If the pipeline takes 20 minutes, adding hooks locally doesn't make the pipeline faster. We've just moved the problem. The day the hook passes but CI fails, we're at the same point as before, except we've wasted more time.&lt;/p&gt;

&lt;p&gt;And if CI feedback isn't clear, it's rarely a tooling problem. It's often that we have one big step doing too many things, that errors are buried in logs, that nobody took the time to make it readable. Hooks don't solve any of that.&lt;/p&gt;

&lt;p&gt;The real question is: how do we reduce the feedback loop time and make it clearer when it fails. And the answer is rarely "add another layer locally". So what do we do?&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing the source
&lt;/h2&gt;

&lt;p&gt;Rather than compensating locally, we should invest in the Developer eXperience of our pipeline.&lt;/p&gt;

&lt;p&gt;First, split CI into clear, parallelized steps. One step for lint, one for tests, one for the build. If lint fails, we see it immediately — no need to dig through logs of a monolithic step. And if steps run in parallel, we reduce total time.&lt;/p&gt;

&lt;p&gt;Next, have notifications when CI fails. We shouldn't have to manually check whether the pipeline passed. A Slack message, an email, a GitHub notification... whatever, but we need to know quickly.&lt;/p&gt;

&lt;p&gt;And finally, make errors readable. When something fails, we should understand why in a few seconds, not after 5 minutes of reading logs. It's a one-time effort that benefits the whole team, unlike hooks which remain an individual solution.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 If you still want a hook while improving CI, &lt;a href="https://github.com/lint-staged/lint-staged" rel="noopener noreferrer"&gt;lint-staged&lt;/a&gt; lets you run formatting and linting only on staged files, with automatic fixing. It doesn't block the flow — it's an acceptable compromise during the transition.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But be careful not to put everything in the hook. Formatting and linting work well in pre-commit because they're fast and auto-fixable: run, fix, move on. Secret detection is another legitimate case: if CI catches it, it's already too late — the secret is in the git history. The pre-commit hook is the only place where blocking makes sense. Tests are different. They're slow, they fail for legitimate reasons (a red test in TDD for example), and they have nothing to auto-fix. Putting them in a hook, whether pre-commit or pre-push, is falling back into the problem we're trying to solve: blocking the flow to force "perfect" code before being able to collaborate. Tests are CI's job.&lt;/p&gt;

&lt;p&gt;But with the arrival of AI agents, the problem takes on a whole new dimension.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI amplifies the problem, the commit changes its role
&lt;/h2&gt;

&lt;p&gt;With AI, the commit is no longer just a save — it's a supervision mechanism. AI moves fast, it touches many files, and we don't read every line in real time. We need small increments to stay in control: reviewing a readable diff rather than 20 files changed at once, doing a precise &lt;code&gt;revert&lt;/code&gt; if the AI goes in the wrong direction. The faster the AI goes, the more we need to commit often. And the more we commit, the more hooks become a bottleneck. It's a paradox: the tool meant to "ensure quality" is precisely what prevents the mechanism that lets us control the quality of the AI's work.&lt;/p&gt;

&lt;p&gt;And when a developer uses &lt;code&gt;--no-verify&lt;/code&gt;, you might think they're in a rush or being careless. But when an AI — with no ego, no impatience, no laziness — also bypasses hooks, that says something else. Concrete example: we ask the AI to add a field to a form. An unrelated test fails in the pre-commit hook. The AI can't commit. We told it not to touch the tests. But the hook blocks it. So it does what a dev would do: it works around it. It adds code to make the test pass without directly modifying it, or it uses &lt;code&gt;--no-verify&lt;/code&gt;. The result: the AI spirals, code quality degrades, and we end up having to revert everything because we couldn't commit before things went off the rails. If even an emotionless agent bypasses hooks, the mechanism is the problem, not the people.&lt;/p&gt;

&lt;p&gt;Yet, we still want the AI to run tests, to check the lint. The problem isn't the checks — it's that git hooks are a single mechanism for two actors with opposing needs. Humans want freedom: commit an intermediate state, try something, go back. AI needs checks, but adapted to it, with feedback we control.&lt;/p&gt;

&lt;p&gt;The AI still needs to actually run those checks, though. With Claude Code for example, you can write instructions in the project's &lt;a href="http://claude.md/" rel="noopener noreferrer"&gt;CLAUDE.md&lt;/a&gt; that the agent follows every session, like "run tests after every modification". And if the conversation context gets compacted and instructions might be lost, you can put them in a dedicated skill to make sure they're always there.&lt;/p&gt;

&lt;p&gt;The remaining question is: what happens when it fails? That's where it gets interesting. Tools like Claude Code offer lifecycle hooks internal to the agent: you can configure a script that runs when a command fails (for example tests), and that injects context into the agent's conversation. Concretely, when tests fail, instead of blocking the commit, the hook guides the AI: "Analyze whether this failure is related to your changes. If yes, fix it. If not, inform the developer." It's not a rigid rule, it's guidance. The AI receives the context and makes a judgment. If the failing test is directly related to what it just modified, it fixes it on its own and continues. If it's an unrelated test, it commits to save the current state and informs us: "This test failed but it has nothing to do with my changes. Want to look at it together?"&lt;/p&gt;

&lt;p&gt;The git hook applies a blind rule — it passes or it blocks, for everyone, without distinction. The agent hook provides context and leaves judgment to the AI, while returning control to the developer. And it doesn't stop at local: the agent can also react to CI events, receive a failure notification, and analyze or fix the error automatically.&lt;/p&gt;

&lt;p&gt;Concretely, with Claude Code, it looks like this in the project's &lt;code&gt;.claude/settings.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PostToolUseFailure"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"if"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm run test|vitest)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"echo '{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;additionalContext&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Some tests failed. Analyze whether these failures are related to your changes. If yes, fix them. If not, commit your changes and inform the developer about the failing tests unrelated to your work.&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}'"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hook only triggers when &lt;code&gt;npm run test&lt;/code&gt; or &lt;code&gt;vitest&lt;/code&gt; fails. It doesn't inject a rule — it injects context that the AI uses to decide on the course of action.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 To go further on Claude Code hooks (&lt;code&gt;PostToolUseFailure&lt;/code&gt;, &lt;code&gt;additionalContext&lt;/code&gt;, &lt;code&gt;matcher&lt;/code&gt;, etc.), the full documentation is available here: &lt;a href="https://code.claude.com/docs/hooks-guide" rel="noopener noreferrer"&gt;https://code.claude.com/docs/hooks-guide&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  One tool, multiple contexts
&lt;/h2&gt;

&lt;p&gt;What I'm describing here applies to a specific context: a team in a company, with CI, and developers who work together daily. In this setting, hooks compensate for a problem we have the means to solve differently.&lt;/p&gt;

&lt;p&gt;But git hooks didn't come from nowhere. They were designed for projects where contributors are numerous, at very different skill levels, and where nobody has a grasp on the entire project. That's exactly the case with open source.&lt;/p&gt;

&lt;p&gt;On an open source project, the constraints are different. Contributors don't necessarily know the project's conventions, they have very different local setups, and they sometimes only contribute once. An occasional contributor who opens a PR isn't going to spend 20 minutes figuring out why the pipeline failed. If a hook fixes their formatting and flags a lint error before they even push, that's time saved for everyone: for them and for the maintainers who review.&lt;/p&gt;

&lt;p&gt;In this context, hooks don't compensate for a bad CI. They serve as an accessible safety net that reduces noise in PRs and accelerates feedback for people who might only contribute once. It's a legitimate use, and that's why we find them in many well-maintained open source projects. Next.js, Angular, webpack, Storybook, NestJS, Prisma... all use hooks to run formatting and linting on staged files before each commit. Not tests, not the build. Just what's fast and auto-fixable.&lt;/p&gt;

&lt;p&gt;Git hooks aren't a bad tool. In open source, they're a proven safety net. But in a company team, with CI and the means to invest in it, using them to compensate for a slow feedback loop is putting on a band-aid. The problem isn't local — it's in the pipeline. That's where we need to act.&lt;/p&gt;

</description>
      <category>git</category>
      <category>ai</category>
      <category>productivity</category>
      <category>devops</category>
    </item>
    <item>
      <title>Git hooks : tout n'est pas bon à bloquer</title>
      <dc:creator>Jérémy Chauvin</dc:creator>
      <pubDate>Tue, 28 Apr 2026 06:01:05 +0000</pubDate>
      <link>https://forem.com/singebob/git-hooks-tout-nest-pas-bon-a-bloquer-4p7b</link>
      <guid>https://forem.com/singebob/git-hooks-tout-nest-pas-bon-a-bloquer-4p7b</guid>
      <description>&lt;p&gt;Les git hooks, c’est une pratique qu’on voit de plus en plus dans les projets. On l’adopte souvent parce qu’on l’a vu ailleurs, ou parce que ça semble être une bonne idée pour garantir la qualité du code. Mais est-ce que c’est vraiment le cas ?&lt;/p&gt;

&lt;p&gt;Avant d’aller plus loin, il faut expliquer ce qu’est un hook git. Avec git on peut exécuter des scripts lorsqu’on veut créer un commit, push etc (pre-commit, pre-push etc).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;a href="https://github.com/typicode/husky" rel="noopener noreferrer"&gt;Husky&lt;/a&gt; est un très bon outil pour découvrir et faire ses premiers hooks&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En utilisant un pre-commit hook, lorsque l’on entre la commande “git commit”, un script est joué. Si celui-ci échoue, le commit est annulé. On est alors obligé de résoudre le problème afin de pouvoir commit.&lt;/p&gt;

&lt;p&gt;Pour faciliter la collaboration dans l'équipe, on pourrait alors se dire "Super, je vais pouvoir vérifier que" :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;que tous mes tests passent&lt;/li&gt;
&lt;li&gt;que mon linter passe&lt;/li&gt;
&lt;li&gt;que mon formateur passe&lt;/li&gt;
&lt;li&gt;que le nom de mon commit respecte bien les conventions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;C’est là que les problèmes commencent. Parce que oui, le feedback sera plus rapide, mais à quel prix ?&lt;/p&gt;

&lt;h2&gt;
  
  
  Le commit n'est pas une livraison
&lt;/h2&gt;

&lt;p&gt;Avec les hooks, on lance les tests, le linter, le formateur et la vérification du nom de commit à chaque fois qu'on veut commit. Faire un commit devient lent et frustrant. On est dans notre flow, on a avancé sur notre feature, et on doit attendre que tout passe avant de pouvoir partager notre travail.&lt;/p&gt;

&lt;p&gt;Et au final qu’est-ce qui se passe ? Si on finit par contourner les hooks avec &lt;code&gt;--no-verify&lt;/code&gt;, c’est pour retrouver un flow de dev rapide.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Git a une option &lt;a href="https://git-scm.com/docs/githooks#_pre_commit" rel="noopener noreferrer"&gt;&lt;code&gt;--no-verify&lt;/code&gt;&lt;/a&gt; sur ses commandes pour ignorer les hooks&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;L’autre problème c’est que les hooks nous poussent vers du code “parfait” à chaque commit. Mais un commit ce n’est pas une livraison. Prenons un exemple concret : on travaille en TDD, on vient d’écrire un test rouge qui décrit le comportement qu’on veut implémenter. On veut commit ce test avant de passer à l’implémentation. Sauf que le hook pre-commit lance le build ou le linter ou le type check, ça échoue, et le commit est bloqué. On est forcé soit d’implémenter dans la foulée, soit de faire &lt;code&gt;--no-verify&lt;/code&gt;. Le cycle red-green-refactor, qui repose justement sur des états intermédiaires, devient pénible.&lt;/p&gt;

&lt;p&gt;C’est le principe même du commit : sauvegarder un état pour pouvoir revenir en arrière si besoin. Avec des hooks trop stricts, on nous demande du code parfait à chaque sauvegarde. On perd cette liberté.&lt;/p&gt;

&lt;p&gt;Et le problème ne s’arrête pas au commit. Même quand le hook pre-commit se limite au lint et au build, on retrouve souvent les tests dans un hook pre-push. Résultat : on peut commit en local, mais impossible de push tant que les tests ne passent pas. Si on fait du pair ou du mob programming et qu’on veut partager un état de travail en cours, c’est bloqué. Si on a besoin d’un avis d’un collègue sur une approche avant de continuer, c’est bloqué. On retombe dans la même logique : du code “parfait” pour pouvoir collaborer.&lt;/p&gt;

&lt;p&gt;Et ce n'est pas le seul problème…&lt;/p&gt;

&lt;h2&gt;
  
  
  Double pain, zero gain
&lt;/h2&gt;

&lt;p&gt;L’autre problématique qu’on crée avec les hooks, c’est la duplication. Les mêmes vérifications tournent en local via les hooks, puis une deuxième fois dans la pipeline (Github Actions, Gitlab CI etc). On attend que les hooks passent, puis on attend que la CI relance exactement la même chose. On ne gagne pas de temps, on en perd.&lt;/p&gt;

&lt;p&gt;Et ce n’est pas juste une question de temps. On se retrouve à maintenir les checks à deux endroits : la config des hooks et la pipeline. On met à jour une option dans une commande côté CI mais on oublie de le faire côté hooks, ou l’inverse. Les deux divergent, et on ne s’en rend compte que quand ça casse.&lt;/p&gt;

&lt;p&gt;De plus, on risque de retomber dans le piège du "ça marche sur ma machine", ou justement l’inverse. L’environnement local et la CI ce n’est pas la même chose. Les versions des outils, les dépendances, la config... il y a de nombreuses raisons pour que le résultat soit différent. On se rajoute une charge cognitive en plus pour comprendre pourquoi ça passe chez nous et pas dans la pipeline, ou l’inverse.&lt;/p&gt;

&lt;p&gt;Finalement, c’est la CI qui décide si on peut merge ou pas. C’est elle la source de vérité. Si on lui fait confiance pour bloquer un merge, pourquoi dupliquer ce travail en local ?&lt;/p&gt;

&lt;p&gt;Mais alors, si les hooks posent autant de problèmes, pourquoi on continue à les utiliser ?&lt;/p&gt;

&lt;h2&gt;
  
  
  Ce qu'on compense vraiment
&lt;/h2&gt;

&lt;p&gt;Le vrai problème c’est la feedback loop de notre CI. La pipeline prend 20 minutes, on ne reçoit aucune notification en cas d’échec, et surtout, tout reste très obscur. Car on a une grosse étape qui mélange plein de trucs et pour savoir ce qui a cassé on doit aller fouiller dans les logs. C’est frustrant.&lt;/p&gt;

&lt;p&gt;Les hooks c’est une réponse à cette frustration. On veut un feedback plus rapide, plus clair, plus proche de nous. Et ça se comprend.&lt;/p&gt;

&lt;p&gt;Dans tous les cas, les hooks c’est un pansement, pas une solution. On traite le symptôme mais pas la cause. Le vrai sujet c’est pas "comment avoir un feedback plus vite en local", c’est "pourquoi mon feedback est lent et pas clair à la base".&lt;/p&gt;

&lt;p&gt;Si la pipeline met 20 minutes, rajouter des hooks en local ça ne rend pas la pipeline plus rapide. On a juste déplacé le problème. Le jour où le hook passe mais la CI échoue, on est au même point qu’avant, sauf qu’on a perdu du temps en plus.&lt;/p&gt;

&lt;p&gt;Et si le feedback de la CI n’est pas clair, c’est rarement un problème d’outillage. C’est souvent qu’on a une grosse étape qui fait trop de choses, que les erreurs sont noyées dans les logs, que personne n’a pris le temps de rendre ça lisible. Les hooks ne résolvent rien de tout ça.&lt;/p&gt;

&lt;p&gt;La vraie problématique c’est : comment réduire le temps du feedback loop et le rendre plus clair quand ça échoue. Et la réponse, c’est rarement "rajouter une couche en local". Alors on fait quoi ?&lt;/p&gt;

&lt;h2&gt;
  
  
  Réparer la source
&lt;/h2&gt;

&lt;p&gt;Plutôt que de compenser en local, on devrait investir dans la Developer eXperience de notre pipeline.&lt;/p&gt;

&lt;p&gt;Déjà, découper la CI en étapes claires et parallélisées. Une étape pour le lint, une pour les tests, une pour le build. Si le lint échoue, on le voit tout de suite, on n’a pas besoin d’aller fouiller dans les logs d’une étape monolithique. Et si les étapes tournent en parallèle, on réduit le temps total.&lt;/p&gt;

&lt;p&gt;Ensuite, avoir des notifications quand la CI échoue. On ne devrait pas avoir à aller vérifier manuellement si la pipeline est passée. Un message Slack, un mail, une notif Github... peu importe, mais on doit le savoir rapidement.&lt;/p&gt;

&lt;p&gt;Et enfin, rendre les erreurs lisibles. Quand ça échoue, on doit comprendre pourquoi en quelques secondes, pas en 5 minutes de lecture de logs. C’est un effort qui se fait une fois et qui profite à toute l’équipe, contrairement aux hooks qui restent une solution individuelle.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Si on veut quand même un hook en attendant d’améliorer la CI, &lt;a href="https://github.com/lint-staged/lint-staged" rel="noopener noreferrer"&gt;lint-staged&lt;/a&gt; permet de ne lancer le formatage et le lint que sur les fichiers stagés, avec correction automatique. Ça ne bloque pas le flow, c’est un compromis acceptable le temps de la transition.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Mais attention à ne pas tout mettre dans le hook. Le formatage et le lint fonctionnent bien en pre-commit parce qu’ils sont rapides et auto-corrigeables : on lance, ça corrige, on continue. La détection de secrets c’est un autre cas légitime : si la CI l’attrape, c’est déjà trop tard, le secret est dans l’historique git. Le hook pre-commit est le seul endroit où le bloquer a du sens. Les tests, c’est différent. Ils sont lents, ils échouent pour des raisons légitimes (un test rouge en TDD par exemple), et ils n’ont rien à corriger automatiquement. Les mettre dans un hook, que ce soit en pre-commit ou en pre-push, c’est retomber dans le problème qu’on essaie de résoudre : bloquer le flow pour forcer du code "parfait" avant de pouvoir collaborer. Les tests, c’est le rôle de la CI.&lt;/p&gt;

&lt;p&gt;Mais avec l’arrivée des agents IA, le problème prend une autre dimension.&lt;/p&gt;

&lt;h2&gt;
  
  
  L’IA amplifie le problème, le commit change de rôle
&lt;/h2&gt;

&lt;p&gt;Avec l’IA, le commit n’est plus juste une sauvegarde, c’est un mécanisme de supervision. L’IA va vite, elle touche beaucoup de fichiers, et on ne lit pas chaque ligne en temps réel. On a besoin de petits incréments pour garder le contrôle : relire un diff lisible plutôt que 20 fichiers changés d’un coup, faire un &lt;code&gt;revert&lt;/code&gt; précis si l’IA part dans la mauvaise direction. Plus l’IA va vite, plus on a besoin de commiter souvent. Et plus on commit souvent, plus les hooks deviennent un frein. C’est un paradoxe : l’outil censé "garantir la qualité" empêche justement le mécanisme qui nous permet de contrôler la qualité du travail de l’IA.&lt;/p&gt;

&lt;p&gt;Et quand un développeur fait &lt;code&gt;--no-verify&lt;/code&gt;, on peut se dire qu’il est pressé ou négligent. Mais quand une IA — sans ego, sans impatience, sans flemme — contourne aussi les hooks, ça dit autre chose. Exemple concret : on demande à l’IA d’ajouter un champ dans un formulaire. Un test sans rapport échoue dans le hook pre-commit. L’IA ne peut pas commiter. On lui a dit de ne pas toucher aux tests. Mais le hook la bloque. Alors elle fait ce qu’un dev ferait : elle contourne. Elle rajoute du code pour faire passer le test sans le modifier directement, ou elle fait &lt;code&gt;--no-verify&lt;/code&gt;. Le résultat : l’IA part en roue libre, le code se dégrade, et on finit par devoir tout revert parce qu’on n’a pas pu commiter avant que ça dérape. Si même un agent sans émotion contourne les hooks, c’est que le mécanisme est le problème, pas les gens.&lt;/p&gt;

&lt;p&gt;Pourtant, on veut quand même que l’IA lance les tests, qu’elle vérifie le lint. Le problème c’est pas les vérifications, c’est que les git hooks sont un mécanisme unique pour deux acteurs aux besoins opposés. L’humain veut de la liberté : commiter un état intermédiaire, essayer un truc, revenir en arrière. L’IA a besoin de vérifications, mais adaptées à elle, avec un feedback qu’on contrôle.&lt;/p&gt;

&lt;p&gt;Encore faut-il que l’IA lance les vérifications. Avec Claude Code par exemple, on peut écrire dans le &lt;a href="http://claude.md/" rel="noopener noreferrer"&gt;CLAUDE.md&lt;/a&gt; du projet des instructions que l’agent suit à chaque session, comme "lance les tests après chaque modification". Et si le contexte de conversation est compacté et que les instructions risquent d’être perdues, on peut les mettre dans un skill dédié pour être sûr qu’elles sont toujours là.&lt;/p&gt;

&lt;p&gt;Reste la question : que se passe-t-il quand ça échoue ? C’est là que ça devient intéressant. Des outils comme Claude Code proposent des hooks de cycle de vie internes à l’agent : on peut configurer un script qui s’exécute quand une commande échoue (par exemple les tests), et qui injecte du contexte dans la conversation de l’agent. Concrètement, quand les tests échouent, au lieu de bloquer le commit, le hook guide l’IA : "Analyse si cet échec est lié à tes changements. Si oui, corrige. Si non, informe le développeur." Ce n’est pas une règle rigide, c’est du guidage. L’IA reçoit le contexte et juge. Si le test qui échoue est directement lié à ce qu’elle vient de modifier, elle le corrige toute seule et continue. Si c’est un test sans rapport, elle commit pour sauvegarder l’état actuel et nous informe : "Ce test a échoué mais ça n’a rien à voir avec mes changements. Tu veux qu’on regarde ensemble ?"&lt;/p&gt;

&lt;p&gt;Le git hook applique une règle aveugle — ça passe ou ça bloque, pour tout le monde, sans distinction. Le hook d’agent donne du contexte et laisse le jugement à l’IA, tout en rendant le contrôle au développeur. Et ça ne s’arrête pas au local : l’agent peut aussi réagir aux événements de la CI, recevoir une notification d’échec et analyser ou corriger l’erreur automatiquement.&lt;/p&gt;

&lt;p&gt;Concrètement, avec Claude Code, ça ressemble à ça dans le &lt;code&gt;.claude/settings.json&lt;/code&gt; du projet :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PostToolUseFailure"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"if"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash(npm run test|vitest)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"echo '{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;additionalContext&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Des tests ont échoué. Analyse si ces échecs sont liés à tes changements. Si oui, corrige-les. Si non, commit tes changements et informe le développeur des tests qui échouent sans rapport avec ton travail.&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}'"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Le hook ne se déclenche que quand &lt;code&gt;npm run test&lt;/code&gt; ou &lt;code&gt;vitest&lt;/code&gt; échoue. Il n'injecte pas une règle, il injecte du contexte que l'IA utilise pour juger de la marche à suivre.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Pour aller plus loin sur les hooks Claude Code (&lt;code&gt;PostToolUseFailure&lt;/code&gt;, &lt;code&gt;additionalContext&lt;/code&gt;, &lt;code&gt;matcher&lt;/code&gt;, etc.), la documentation complète est disponible ici : &lt;a href="https://code.claude.com/docs/fr/hooks-guide" rel="noopener noreferrer"&gt;https://code.claude.com/docs/fr/hooks-guide&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Un outil, plusieurs contextes&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Ce que je décris ici s’applique à un contexte précis : une équipe en entreprise, avec une CI, et des développeurs qui travaillent ensemble au quotidien. Dans ce cadre, les hooks compensent un problème qu’on a les moyens de résoudre autrement.&lt;/p&gt;

&lt;p&gt;Mais les git hooks ne viennent pas de nulle part. Ils ont été pensés pour des projets où les contributeurs sont nombreux, de niveaux très différents, et où personne ne maîtrise l’ensemble du projet. C’est exactement le cas de l’open source.&lt;/p&gt;

&lt;p&gt;Sur un projet open source, les contraintes sont autres. Les contributeurs ne connaissent pas forcément les conventions du projet, ils ont des setups locaux très différents, et ils ne contribuent parfois qu’une seule fois. Un contributeur occasionnel qui ouvre une PR ne va pas passer 20 minutes à comprendre pourquoi la pipeline a échoué. Si un hook lui corrige le formatage et lui signale une erreur de lint avant même de push, c’est du temps gagné pour tout le monde : pour lui et pour les mainteneurs qui relisent.&lt;/p&gt;

&lt;p&gt;Dans ce contexte, les hooks ne compensent pas une mauvaise CI. Ils servent de filet de sécurité accessible, qui réduit le bruit dans les PRs et accélère le feedback pour des gens qui ne contribuent peut-être qu’une seule fois. C’est un usage légitime, et c’est d’ailleurs pour ça qu’on les retrouve dans beaucoup de projets open source bien maintenus. Next.js, Angular, webpack, Storybook, NestJS, Prisma... tous utilisent des hooks pour lancer le formatage et le lint sur les fichiers stagés avant chaque commit. Pas les tests, pas le build. Juste ce qui est rapide et auto-corrigeable.&lt;/p&gt;

&lt;p&gt;Les git hooks ce n’est pas un mauvais outil. En open source, c’est un filet de sécurité qui a fait ses preuves. Mais dans une équipe en entreprise, avec une CI et les moyens d’investir dedans, s’en servir pour compenser un feedback loop lent c’est mettre un pansement. Le problème n’est pas en local, il est dans la pipeline. C’est là qu’il faut agir.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>french</category>
      <category>productivity</category>
      <category>devops</category>
    </item>
    <item>
      <title>Tester son interface efficacement : des patterns pour des tests d’UI robustes</title>
      <dc:creator>Jérémy Chauvin</dc:creator>
      <pubDate>Thu, 13 Mar 2025 16:53:40 +0000</pubDate>
      <link>https://forem.com/singebob/tester-son-interface-efficacement-des-patterns-pour-des-tests-dui-robustes-2402</link>
      <guid>https://forem.com/singebob/tester-son-interface-efficacement-des-patterns-pour-des-tests-dui-robustes-2402</guid>
      <description>&lt;p&gt;&lt;em&gt;Article co-écrit avec &lt;a class="mentioned-user" href="https://dev.to/manon_carbonnel"&gt;@manon_carbonnel&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tester l’interface (UI) est un défi&lt;/strong&gt; : les tests doivent être &lt;strong&gt;fiables, lisibles et maintenables&lt;/strong&gt; dans le temps, tout en restant suffisamment souples pour suivre les évolutions du produit. Malheureusement, l’UI est amenée à évoluer régulièrement, et ces tests sont souvent &lt;strong&gt;fragiles&lt;/strong&gt; et difficiles à faire évoluer si leur conception n’est pas rigoureuse. Nous voulons également des tests cohérents avec des parcours réalistes.&lt;/p&gt;

&lt;p&gt;Cet article explore des &lt;strong&gt;patterns éprouvés&lt;/strong&gt; pour améliorer la qualité des tests d’UI. Ces tests sont aussi l’occasion de se mettre à la place des utilisateur·ices de nos applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  User Facing Attributes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Ce pattern propose d’utiliser des sélecteurs basés sur des attributs ou propriétés visibles par l’utilisateur·ice&lt;/strong&gt; (rôles accessibles, labels, textes, etc.) pour identifier et interagir avec les éléments de l'interface. Cela permet de rendre les tests plus intuitifs et orientés vers l'expérience réelle de l'utilisateur·ice, en étant moins dépendants de CSS, tout en favorisant des pratiques de développement prenant en compte l’accessibilité.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 C’est aujourd’hui l’approche préconisée par la majorité des outils d’automatisation de navigateur comme &lt;a href="https://playwright.dev/docs/locators" rel="noopener noreferrer"&gt;Playwright&lt;/a&gt;.&lt;br&gt;
Si vous utilisez &lt;a href="https://docs.cypress.io/app/core-concepts/best-practices#Selecting-Elements" rel="noopener noreferrer"&gt;Cypress&lt;/a&gt;, bien que la documentation évoque Testing Library, elle préconise l’utilisation de &lt;code&gt;data-test-id&lt;/code&gt;.&lt;br&gt;
Mais nous ne sommes pas d’accord avec cette recommandation :D.&lt;br&gt;
Dans la même idée, utiliser des locators basés sur le CSS ou le XPath ne sont pas recommandés, car le DOM peut souvent changer, ce qui conduit à des tests non résilients.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Exemples de code pour accéder aux éléments du DOM d’une page web
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Exemple d’utilisation avec Testing Library&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// tests/homepage.spec.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HomePage - User Facing Attributes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;devrait afficher un titre contenant "Playwright" et un lien "Get started" visible&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://playwright.dev/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Sélection basée sur des attributs exposés à l'utilisateur·ice&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;heading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/Playwright/i&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getStartedLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/Get started/i&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getStartedLink&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeVisible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Exemple d’utilisation avec Playwright&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// tests/homepage.spec.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Locator&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PlaywrightHomePage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../pages/PlaywrightHomePage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test du site Playwright via User Facing Attributes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Vérifier que le titre principal contient "Playwright" et que le lien "Get started" est visible&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://playwright.dev/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Sélection basée sur des attributs exposés à l'utilisateur·ice&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;heading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getStartedLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/Get started/i&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toContainText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Playwright&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getStartedLink&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeVisible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Avantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Robustesse des tests :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Les tests sont moins susceptibles de casser lors de modifications techniques (comme des changements d'attributs CSS ou ordre des balises dans le DOM).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Alignement avec l'UX :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Les sélecteurs utilisés correspondent à ce que voit et utilise réellement l'utilisateur·ice, améliorant ainsi la pertinence des tests.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Promotion des bonnes pratiques d'accessibilité :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Toutes les interfaces ne sont pas toujours dotées d'attributs ou de rôles pertinents, ce pattern incite donc développer des interfaces accessibles et bien structurées.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lisibilité et clarté :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Les tests sont plus explicites, car ils décrivent les éléments de l'interface tels qu'une personne les perçoit.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Inconvénients
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dépendance au contenu textuel :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Les tests peuvent devenir fragiles si les libellés ou textes changent fréquemment, même si la fonctionnalité reste correcte.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Moins de contrôle sur des sélecteurs complexes :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pour certaines interactions spécifiques ou des éléments très dynamiques (comme un élément dans un tableau ou une liste de données), il peut être nécessaire d'utiliser des sélecteurs techniques en complément ou remplacement.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Page Object Model
&lt;/h2&gt;

&lt;p&gt;Son objectif principal est de &lt;strong&gt;séparer la logique de test&lt;/strong&gt; (les scénarios et assertions) de la &lt;strong&gt;logique d'interaction avec l'interface&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemples de code avec Playwright
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// pages/PlaywrightHomePage.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Locator&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlaywrightHomePage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Locator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// On cible ici le titre principal de la page (par exemple, l'élément h1)&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Méthode pour naviguer vers la page d'accueil&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://playwright.dev/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Méthode pour récupérer le texte du titre&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getHeaderText&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Exemple d’utilisation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// tests/homepage.spec.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PlaywrightHomePage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../pages/PlaywrightHomePage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test du site Playwright&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Vérifier que le titre principal contient "Playwright"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Instanciation de la page via notre Page Object&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;homePage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PlaywrightHomePage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;homePage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;homePage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHeaderText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;headerText&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toContain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Playwright&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Avantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Séparation des responsabilités :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Le POM sépare la logique de test de l’implémentation de l’interface. Cela permet aux tests de se concentrer sur la validation du comportement métier.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Modularité et évolutivité :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Chaque page ou composant est représenté par une classe spécifique, facilitant ainsi l’organisation et l’évolution de la suite de tests.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Maintenance facilitée :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lorsqu'une modification est apportée à l'interface (changement de sélecteur, structure HTML modifiée…), il suffit de mettre à jour la classe correspondante, sans toucher aux tests eux-mêmes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Réutilisabilité :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Les méthodes et sélecteurs encapsulés dans un objet peuvent être réutilisés dans plusieurs tests, réduisant ainsi la duplication de code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lisibilité et clarté des tests :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;En déléguant les interactions à des objets dédiés, les scénarios de tests restent concis et lisibles. On peut ainsi comprendre rapidement l’intention du test sans se perdre dans les détails d’implémentation.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Inconvénients
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Risque de duplication si mal structuré :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sans une bonne conception, on peut se retrouver avec des classes qui dupliquent des comportements similaires pour des composants récurrents, au lieu d’extraire des composants communs. Dans le cas où on trouverait plusieurs fois le même composant sur une page, il suffit d’y accéder en précisant le bloc parent dans le sélecteur.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Couplage si contenu dans une librairie à part :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Conserver le POM dans un repository / une librairie à part entraîne des problèmes d’alignement des sélecteurs lors de mise à jour des pages.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Screenplay Pattern : alternative au POM
&lt;/h2&gt;

&lt;p&gt;Le Screenplay Pattern est une approche pour structurer les tests d'UI en mettant l'accent sur les actions et les intentions des utilisateur·ices, plutôt que sur la structure technique des pages. Particulièrement utile pour des &lt;strong&gt;suites de tests larges et évolutives&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Au lieu de manipuler directement les éléments de l’UI via un Page Object Model (POM), il introduit des "acteur·ices" qui interagissent avec l'interface en utilisant des "tâches" et des "questions".&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemples de code avec Playwright
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Définition des intéractions&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EnterText&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;into&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Click&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Définition des tâches&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Login&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;withCredentials&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;EnterText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;into&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;EnterText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;into&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Click&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#login-button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Définition des questions&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IsLoggedIn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;answeredBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#welcome-message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;isVisible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Exemple d’utilisation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// tests/login.spec.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;IsLoggedIn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./login-screenplay&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice peut se connecter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://example.com/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// L'utilisateur·ice joue le rôle d'un·e acteur·ice réalisant une tâche&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withCredentials&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;securepassword&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Vérification de la connexion&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loggedIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;IsLoggedIn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;answeredBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loggedIn&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Avantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Modularité :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Les interactions et tâches sont réutilisables.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lisibilité :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Le code ressemble plus à un scénario utilisateur.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Maintenance facilitée :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Modifier l’implémentation d’une interaction ne casse pas toute la suite de tests.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scalabilité :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Facilite l’ajout de nouvelles tâches sans dupliquer du code.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Inconvénients
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Complexité initiale :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Plus de fichiers et d'abstraction qu'un simple Page Object Model qui est parfois suffisant pour de petits tests simple.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Courbe d’apprentissage :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nécessite de bien comprendre la séparation entre acteurs, tâches et interactions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Outils et bibliothèques populaires pour des test d’UI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Testing Library
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://testing-library.com/" rel="noopener noreferrer"&gt;Testing library&lt;/a&gt; est une solution légère pour tester des UI en interagissant avec le DOM de manière similaire à une personne. Son approche repose sur la recherche et l'interaction avec les éléments via leurs &lt;strong&gt;user-facing attributes.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Playwright
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;Playwright&lt;/a&gt; est un outil d'automatisation de navigateurs conçu pour offrir une &lt;strong&gt;developer experience&lt;/strong&gt; confortable et puissante. Il prend en charge plusieurs langages (TypeScript, JavaScript, Python, C#, Java) et permet de tester des applications sur différents navigateurs (Chromium, Firefox, WebKit) et plateformes (Windows, Linux, macOS). Son API facilite la manipulation du DOM et intègre nativement les &lt;strong&gt;user-facing attributes&lt;/strong&gt; pour interagir avec les éléments. Playwright se distingue également par ses fonctionnalités avancées comme le &lt;strong&gt;record &amp;amp; replay&lt;/strong&gt;, les &lt;strong&gt;tests en parallèle&lt;/strong&gt;, et le &lt;strong&gt;debugging interactif&lt;/strong&gt; avec des outils visuels comme le trace viewer.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
      <category>french</category>
      <category>testing</category>
    </item>
    <item>
      <title>Mieux tester en optimisant la génération de données de test : Panorama des patterns</title>
      <dc:creator>Jérémy Chauvin</dc:creator>
      <pubDate>Thu, 13 Mar 2025 16:44:47 +0000</pubDate>
      <link>https://forem.com/singebob/mieux-tester-en-optimisant-la-generation-de-donnees-de-test-panorama-des-patterns-1cde</link>
      <guid>https://forem.com/singebob/mieux-tester-en-optimisant-la-generation-de-donnees-de-test-panorama-des-patterns-1cde</guid>
      <description>&lt;p&gt;&lt;em&gt;Article co-écrit avec &lt;a class="mentioned-user" href="https://dev.to/manon_carbonnel"&gt;@manon_carbonnel&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Écrire des tests automatisés efficaces ne se résume pas à vérifier que notre code fonctionne : il faut aussi que les tests soient lisibles, maintenables et rapides à écrire. Pour cela, la manière dont on génère les données de test joue un rôle clé.&lt;/p&gt;

&lt;p&gt;Les patterns que nous vous présentons permettent d’éviter de la duplication, de rendre les tests plus clairs et de mieux maîtriser la complexité des objets manipulés.&lt;/p&gt;

&lt;p&gt;Dans cet article, nous allons explorer différentes approches, leurs avantages et leurs limites, et cibler la stratégie à adopter selon le contexte.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pourquoi faire varier ses jeux de données ?
&lt;/h2&gt;

&lt;p&gt;Pour certains tests, il est primordial de rendre visible la variation des données afin d'expliciter la règle métier sous-jacente.&lt;/p&gt;

&lt;p&gt;Par exemple, pour déterminer si un utilisateur est majeur, vous devez modifier son âge dans vos tests et créer deux fixtures. Cependant, ce qui vous intéresse réellement, c'est de voir la règle métier apparaître clairement dans vos tests. Il est crucial de bien mettre en évidence l'âge que vous attribuez.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Ces patterns ne sont pas spécifiques au langage TypeScript que nous avons choisi dans nos exemples, et sont implémentables avec n’importe quel langage généraliste.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Utilisation des Fixtures
&lt;/h2&gt;

&lt;p&gt;Les Fixtures sont des ensembles de données préconfigurées utilisées pour initialiser l'état d'un test. Elles permettent de définir des conditions de test spécifiques et de garantir que les tests sont reproductibles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemples de code pour créer et utiliser des Fixtures en TypeScript
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// personaFixtures.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;johnDoe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john.doe@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="c1"&gt;// ... your full Persona caracteristics, to be used in several tests&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// test.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;johnDoe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./personaFixtures&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should create a user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;johnDoe&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// ...code&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;johnDoe&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Avantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Simplicité et facilité d'utilisation.&lt;/li&gt;
&lt;li&gt;Reproductibilité des tests.&lt;/li&gt;
&lt;li&gt;Utilisation des persona UX&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Inconvénients
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Peuvent devenir difficiles à gérer pour des ensembles de données complexes.&lt;/li&gt;
&lt;li&gt;Moins flexibles pour des variations de données.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Utilisation des Object Mother
&lt;/h2&gt;

&lt;p&gt;Le pattern Object Mother consiste à créer des objets complexes à partir de méthodes de fabrication centralisées. Cela permet de simplifier la création d'objets de test et de garantir la cohérence des données.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemples de code pour créer des objets complexes avec des Object Mothers en TypeScript
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// objectMother.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserMother&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john.doe@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// test.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserMother&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./objectMother&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should create a user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UserMother&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john.doe@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Avec un objet plus complexe :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Les types&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// interfaces.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;customerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Object Mother pour Order&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// orderMother.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./interface&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderMother&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;with2Items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A very specific item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Another specific item&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}];&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;customerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rich customer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;previousValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;previousValue&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;currentValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;withoutItems&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;customerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Poor customer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
            &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;johnDoeBuysATable&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Table&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}];&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;customerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;previousValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;previousValue&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;currentValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exemple d’utilisation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// test.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;OrderMother&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./orderMother&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Order Mother&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should create an order with items&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;OrderMother&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with2Items&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;320&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should create an order without items&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;OrderMother&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withoutItems&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Avantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Centralisation de la création d'objets.&lt;/li&gt;
&lt;li&gt;Facilité de maintenance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Inconvénients
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Peut devenir complexe pour des objets très variés.&lt;/li&gt;
&lt;li&gt;Moins flexible pour des variations spécifiques.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Utilisation des Factory Functions
&lt;/h2&gt;

&lt;p&gt;Les Factory Functions sont des fonctions qui retournent des objets. Elles sont simples à utiliser et permettent de créer des objets de manière concise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemples de code pour créer des objets avec des Factory Functions en TypeScript
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 En TypeScript, l'utilisation du type &lt;strong&gt;&lt;code&gt;Partial&lt;/code&gt;&lt;/strong&gt; offre un avantage supplémentaire. Le type &lt;strong&gt;&lt;code&gt;Partial&lt;/code&gt;&lt;/strong&gt; permet de créer des objets partiels, ce qui signifie que vous pouvez définir uniquement les propriétés nécessaires pour un test spécifique. Cela rend les tests plus lisibles et plus faciles à maintenir. Vous pouvez déstructurer votre type pour rendre votre test plus lisible et explicite.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jane Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jane.doe@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should create a user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jonh Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john.doe@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jonh Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john.doe@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Avantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Simplicité et facilité d'utilisation.&lt;/li&gt;
&lt;li&gt;Flexibilité pour créer des objets avec des variations spécifiques.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Inconvénients
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Moins adapté pour des objets très complexes.&lt;/li&gt;
&lt;li&gt;Peut devenir difficile à gérer pour des ensembles de données importants.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Utilisation des Test Data Builders / Builders
&lt;/h2&gt;

&lt;p&gt;Le pattern Builder permet de construire des objets complexes de manière incrémentale. Il est particulièrement utile pour créer des objets avec des variations spécifiques.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemples de code pour créer des objets complexes avec des builders en TypeScript
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// userBuilder.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserBuilder&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john.doe@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;withName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;UserBuilder&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;withEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;UserBuilder&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// test.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserBuilder&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./userBuilder&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should create a user with custom name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserBuilder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;withName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jane Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jane Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john.doe@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Avec un objet plus complexe:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Les types&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// interfaces.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;customerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test Data Builder pour Order&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ItemBuilder.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./interface&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ItemBuilder&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Default Item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;withName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;withId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;withPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;withQuantity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;quantity&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./interface&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ItemBuilder&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./itemBuilder&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderBuilder&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ItemBuilder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;withPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt; &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;customerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;withCustomerName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;customerName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;withItems&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;previousValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;previousValue&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;currentValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exemple d’utilisation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Simple test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should create an order with default builder&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OrderBuilder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should create an order with 2 items&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OrderBuilder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;withItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ItemBuilder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;withPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ItemBuilder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;withPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;withQuantity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;withId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should create a John Doe's order&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OrderBuilder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;withCustomerName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;customerName&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Avantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Flexibilité pour créer des objets avec des variations spécifiques.&lt;/li&gt;
&lt;li&gt;Facilité de lecture et de maintenance.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Vous pouvez également créer des builders avec des valeurs par défaut. C'est ce que recommande le livre "&lt;a href="http://www.growing-object-oriented-software.com" rel="noopener noreferrer"&gt;Growing Object-Oriented Software, Guided by Tests&lt;/a&gt;". Vous aurez ainsi une ou plusieurs méthodes statiques qui vous permettront de configurer vos tests à partir de personas ou de cas métiers spécifiques.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Inconvénients
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Peut devenir verbeux pour des objets simples.&lt;/li&gt;
&lt;li&gt;Nécessite une configuration initiale.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Nos préférences pour la création de jeu de données
&lt;/h2&gt;

&lt;p&gt;Pour nous, ce qui est important, c'est d'avoir une série de tests qui soit lisible et facile à écrire. C'est pourquoi nous mettons en avant trois critères pour choisir le pattern que nous voulons utiliser :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Visibilité des Variations de Données&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API Fluide et Lisibilité&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simplicité et Flexibilité&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;C’est pour cela que nous préférons les patterns &lt;strong&gt;Factory Function&lt;/strong&gt; et &lt;strong&gt;Test Data Builder.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Nous avons des préférences pour ces patterns, mais parfois nous allons utiliser une fixture ou un object mother, car le nommage métier peut être plus explicite que la simple variation des données, etc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Pourquoi le pattern Factory Function ?
&lt;/h3&gt;

&lt;p&gt;Pour des objets simples et sans profondeur, le pattern Factory Function est une approche efficace. Elle permet de créer des objets de manière concise.&lt;/p&gt;

&lt;p&gt;L'utilisation du type &lt;strong&gt;&lt;code&gt;Partial&lt;/code&gt;&lt;/strong&gt; en TypeScript facilite la création d'objets partiels, ce qui est particulièrement utile pour les tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pourquoi le pattern Test Data Builder ?
&lt;/h3&gt;

&lt;p&gt;Le pattern Builder est particulièrement adapté pour les objets avec plusieurs niveaux de profondeur. Il permet de construire des objets complexes de manière incrémentale, en chaînant des méthodes pour définir les différentes propriétés de l'objet. Cette approche offre une grande flexibilité et permet de voir facilement les variations de données, ce qui est crucial pour valider les tests.&lt;/p&gt;




&lt;h2&gt;
  
  
  Outils et bibliothèques populaires pour la création de jeux de données
&lt;/h2&gt;

&lt;h3&gt;
  
  
  faker.js
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Génération de données fictives réalistes.&lt;/li&gt;
&lt;li&gt;Idéal pour tester des scénarios avec des données variées.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  factory.ts
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Création structurée d'objets de test.&lt;/li&gt;
&lt;li&gt;Idéal pour des objets complexes et des variations spécifiques.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://fakerjs.dev/" rel="noopener noreferrer"&gt;faker.js&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;faker.js&lt;/code&gt; est une bibliothèque populaire pour générer des données fictives. Elle permet de créer des données réalistes pour les tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// fakerExample.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;faker&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;faker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./email.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should generate a fake user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;faker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;faker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;internet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;a href="https://github.com/willryan/factory.ts" rel="noopener noreferrer"&gt;factory.ts&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;factory.ts&lt;/code&gt; est une bibliothèque TypeScript pour créer des objets de test de manière structurée.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// factoryExample.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Factory&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;factory.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;makeFactory&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john.doe@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should create a user with factory.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john.doe@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;h3&gt;
  
  
  À partir de quoi faire varier les données ?
&lt;/h3&gt;

&lt;p&gt;Nous vous recommandons fortement de faire varier vos données à partir de personas UX ou de cas métiers bien identifiés. Ces éléments définiront vos valeurs par défaut pour la plupart des patterns décrits ci-dessus. L'objectif d'avoir ces valeurs par défaut (personas UX ou cas métiers) est de rendre vos tests lisibles et de les utiliser comme documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Où ranger ces patterns dans le code ?
&lt;/h3&gt;

&lt;p&gt;Ces fichiers servant uniquement aux tests, ils ont leur place à leurs côtés. Vous pouvez l’utiliser à côté du test qui l’utilise, mais s’il y a de la réutilisation ailleurs, il faudra créer un dossier et fichier dédié.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/test
    /order
        /order.ts
    /dataBuilders
        /orderBuilder.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La création de jeux de données pour les tests est essentielle pour garantir la qualité et la fiabilité du code. Chaque méthode a ses forces et ses limites, et le choix du bon pattern dépend de la complexité des éléments à générer.&lt;/p&gt;

&lt;p&gt;Il n’existe pas de solution universelle : la clé réside dans une réflexion collective et des décisions alignées avec les besoins de votre projet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pour aller plus loin
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://philippe.bourgau.net/how-to-use-test-data-builders-to-avoid-mocks-and-keep-your-tests-clear/" rel="noopener noreferrer"&gt;How to use Test Data Builders to avoid mocks and keep your tests clear | Philippe Bourgau’s XP Coaching Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.c2.com/?TestDataBuilder" rel="noopener noreferrer"&gt;https://wiki.c2.com/?TestDataBuilder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.growing-object-oriented-software.com" rel="noopener noreferrer"&gt;Growing Object-Oriented Software Guided by Tests&lt;/a&gt; de Steve Freeman et Nat Pryce&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.c2.com/?TestFixture" rel="noopener noreferrer"&gt;https://wiki.c2.com/?TestFixture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://refactoring.guru/design-patterns/factory-method" rel="noopener noreferrer"&gt;https://refactoring.guru/design-patterns/factory-method&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.codeleak.pl/2014/06/test-data-builders-and-object-mother.html" rel="noopener noreferrer"&gt;Test Data Builders and Object Mother: another look&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>testing</category>
      <category>softwarecraft</category>
      <category>french</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Guide pratique de l'utilisation des Linters</title>
      <dc:creator>Jérémy Chauvin</dc:creator>
      <pubDate>Wed, 24 Apr 2024 12:30:54 +0000</pubDate>
      <link>https://forem.com/singebob/guide-pratique-de-lutilisation-des-linters-1d50</link>
      <guid>https://forem.com/singebob/guide-pratique-de-lutilisation-des-linters-1d50</guid>
      <description>&lt;p&gt;Nous avons tous déjà vécu un onboarding sur un projet où on fait des copier/coller d’une autre fonctionnalité qui ressemble à ce qu’on veut faire. Nous réadaptons le code, nous commitons et nous pushons. Nous ouvrons la MR/PR et la revue est catastrophique. Le code que nous avons copié-collé est du code legacy, nous avons 15 fois le même commentaire qui nous dit d'utiliser des &lt;em&gt;const&lt;/em&gt; pour déclarer nos variables, etc. Tout cela nous fait perdre du temps, et ne nous met pas dans les meilleures conditions pour apprécier le projet.&lt;/p&gt;

&lt;p&gt;Dans cet article vous allez (re)découvrir comment les linters peuvent vous éviter ces pièges et vous aider à développer.&lt;/p&gt;

&lt;p&gt;Avant d’aborder les avantages d’un linter, nous allons expliquer ce que c’est&lt;/p&gt;

&lt;h2&gt;
  
  
  Qu’est-ce qu’un linter ?
&lt;/h2&gt;

&lt;p&gt;Techniquement, c’est un outil qui fait de l’analyse statique de votre code donc directement dans votre fichier sans que le code soit build ou soit en train de run. &lt;/p&gt;

&lt;p&gt;Cela permet d’avoir une boucle de feedback très courte 🤩&lt;/p&gt;

&lt;h3&gt;
  
  
  Sévérité
&lt;/h3&gt;

&lt;p&gt;Vous allez retrouver en général deux types de sévérité dans un linter qui sont les &lt;em&gt;Warnings&lt;/em&gt; et les &lt;em&gt;Errors.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Les &lt;em&gt;Warnings&lt;/em&gt; sont des problèmes potentiels qui n'empêchent pas l'exécution du code, mais indiquent des pratiques à améliorer pour maintenir la qualité et la cohérence du code.&lt;/p&gt;

&lt;p&gt;Les &lt;em&gt;Errors&lt;/em&gt; sont des problèmes bloquants qui empêchent le code de fonctionner correctement. Elles doivent être corrigées avant de pouvoir compiler ou exécuter le programme.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🧐 Pour information&lt;br&gt;
Dans la plupart des projets, vous allez retrouver la règle &lt;em&gt;no-warning&lt;/em&gt; dans notre CI. Ce qui fait que si vous avez une règle en &lt;em&gt;warning&lt;/em&gt; qui est détecté alors votre CI va planter.&lt;br&gt;
Personnellement, je n’aime pas cette feature, car elle vous obligent à tout faire d’un coup. Je vous en reparle dans la partie “Mieux refactorer du code legacy”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Rendre l’implicite explicite
&lt;/h2&gt;

&lt;p&gt;En mettant en place un ou des linters, vous allez pouvoir rendre l’implicite &lt;strong&gt;explicite&lt;/strong&gt;, c'est-à-dire faire émerger des règles et des conventions qui peuvent ne pas être documentées ou comprises par tous les membres de l'équipe.&lt;/p&gt;

&lt;p&gt;Par exemple, un linter peut vérifier que vos attributs sont dans l’ordre alphabétique, que vos variables sont bien immuables (en JS, n'utiliser que des &lt;em&gt;const&lt;/em&gt;), que vous respectez les normes sur le nommage de variable, de classes ou de fonctions dans votre projet. Ces règles peuvent sembler mineures, mais elles contribuent à la lisibilité et à la compréhension du code par tous les membres de l'équipe.&lt;/p&gt;

&lt;p&gt;En rendant ces règles explicites grâce à un linter, vous pouvez vous assurer que tout le monde suit les mêmes conventions et que le code soit cohérent et facile à comprendre. Cela peut également faciliter l'intégration de nouveaux membres dans l'équipe, car les règles sont clairement définies et documentées.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apprendre
&lt;/h2&gt;

&lt;p&gt;En utilisant un linter, vous pouvez apprendre de nouvelles pratiques. Les linters peuvent vous aider à découvrir des règles et des conventions que vous ne connaissiez peut-être pas auparavant, ainsi que les raisons pour lesquelles ces règles sont importantes.&lt;/p&gt;

&lt;p&gt;Par exemple, en utilisant un linter pour JavaScript, vous pouvez apprendre que la méthode "reduce" peut être moins performante qu'une boucle "for" dans certaines situations. En comprenant pourquoi cette règle est importante, vous pouvez prendre de meilleures décisions&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(&lt;a href="https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-reduce.md" rel="noopener noreferrer"&gt;https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-reduce.md&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;De plus, les linters peuvent vous aider à améliorer votre code que ça soit sur la lisibilité, la séparation de la logique, la sécurité (&lt;a href="https://snyk.io/fr/" rel="noopener noreferrer"&gt;Snyk&lt;/a&gt;, &lt;a href="https://www.sonarsource.com/products/sonarqube/" rel="noopener noreferrer"&gt;Sonar&lt;/a&gt; etc) et la performance. En comprenant pourquoi ces règles sont importantes, vous pouvez non seulement écrire du code plus propre et plus efficace, mais également vous améliorer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mieux refactorer du code legacy
&lt;/h2&gt;

&lt;p&gt;Lorsque vous travaillez sur une application existante avec du code legacy, un linter peut être un outil très utile pour vous aider à nettoyer et à mettre à jour votre code. Vous pouvez aussi identifier les parties de votre code qui doivent être mises à jour ou supprimées, et suivre votre progression au fil du temps.&lt;/p&gt;

&lt;p&gt;Par exemple, supposons que vous souhaitiez supprimer une bibliothèque (comme Lodash) de votre application. Cependant, le faire d'un coup peut être trop risqué ou trop complexe. Dans ce cas, vous pouvez commencer par ajouter une règle de linter en mode &lt;em&gt;warning&lt;/em&gt; sur l'utilisation de Lodash. Cela vous permettra de savoir chaque fois que vous utilisez Lodash dans votre code et de commencer à le supprimer progressivement. De plus, l’ajouter en mode &lt;em&gt;warning&lt;/em&gt; permet aussi à ce qu’un nouveau ou une personne qui rentre de vacances sache qu’il ne doit plus l’utiliser.&lt;/p&gt;

&lt;p&gt;En suivant le nombre d'avertissements de cette règle, vous pouvez suivre votre progression. Aussi, vous pouvez être sûr que tout nouveau code que vous écrivez ne dépendra pas de Lodash, ce qui facilitera la suppression complète de la bibliothèque à l'avenir.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Je vous conseille fortement de ne pas avoir plus d’une règle en &lt;em&gt;warning&lt;/em&gt; pour ne pas avoir trop de choses à faire d’un coup&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Attention, un linter apporte aussi une certaine complexité, qui peut vous freiner ou être un point de souffrance.&lt;/p&gt;

&lt;p&gt;Par exemple, vous avez deux règles qui, individuellement, semblent cohérentes :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mets en dernier les paramètres qui ont une valeur par défaut&lt;/li&gt;
&lt;li&gt;Trie les paramètres dans l’ordre alphabétique&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tant que vous n’avez pas les deux en même temps, il n’y a aucun problème. Mais si vous avez ça:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Mets en dernier les paramètres qui ont une valeur par défaut&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleThings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Trie les paramètre dans l'ordre alphabétique&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleThings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
     &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vos règles vont se marcher dessus. Pour éviter cela, je vous conseille donc de faire attention à ces deux points.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ajout de règle sans cesse
&lt;/h2&gt;

&lt;p&gt;L'ajout de règles sans limite peut devenir contre-productif et entraver le bon déroulement du projet. Il est important de trouver un équilibre entre la qualité du code et la productivité de l'équipe.&lt;br&gt;
Je vous recommande de ne pas ajouter trop de règles d'un coup, mais plutôt de les introduire progressivement en fonction des besoins du projet et de l'équipe. Il est également utile de régulièrement réévaluer les règles existantes pour s'assurer qu'elles soient toujours pertinentes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Je vous conseille fortement de faire des discussions régulières pour parler des règles de linter, de choisir si vous devez la garder ou rajouter des règles si besoin. Pendant ces discussions il est important de documenter pourquoi vous mettez en place une règle ou pourquoi vous enlevez une règle&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Le nombre idéal de règles dépend du projet et de l'équipe. &lt;/p&gt;

&lt;p&gt;La seule question que vous devez vous poser c’est si la règle est &lt;strong&gt;pertinente&lt;/strong&gt; dans votre contexte. &lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration complexe
&lt;/h2&gt;

&lt;p&gt;La configuration d'un linter peut devenir compliquée avec le temps et nécessitera une maintenance régulière pour rester efficace. Si la configuration n'est pas bien gérée, cela peut entraîner des problèmes tels que des règles contradictoires ou non pertinentes pour le projet. &lt;/p&gt;

&lt;p&gt;Il est important de prendre le temps de comprendre l'historique de la configuration du linter avant de faire des modifications ou de critiquer la configuration actuelle. Il peut être utile de discuter avec les membres de l'équipe qui ont travaillé précédemment sur la configuration  pour comprendre les raisons derrière certaines décisions. &lt;/p&gt;

&lt;p&gt;En outre, il est important de documenter les changements apportés à la configuration du linter et de communiquer ces changements à l'équipe. Cela peut aider à éviter les conflits et à maintenir une configuration cohérente et efficace. &lt;/p&gt;

&lt;h3&gt;
  
  
  Comment gérer la documentation de son linter ?
&lt;/h3&gt;

&lt;p&gt;Je recommande de stocker la documentation de votre linter à proximité du code, dans le même dépôt git&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;❓ Pourquoi proche du code ?&lt;br&gt;
Si vous stockez la documentation du linter dans un outil externe tel que Confluence ou un autre référentiel qui génère un site web à partir de fichiers markdown, vous risquez de rencontrer des problèmes de synchronisation. &lt;br&gt;
Par exemple, quelqu'un peut oublier de mettre à jour la documentation ou vous n'y avez pas accès pour une raison quelconque. &lt;br&gt;
En revanche, si vous stockez la documentation du linter au même endroit que le code, vous réduisez considérablement le risque de désynchronisation. &lt;br&gt;
De plus, cela facilite l'accès à la documentation pour les développeurs qui travaillent sur le projet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Vous pouvez créer un dossier &lt;code&gt;docs&lt;/code&gt; à la racine de votre projet. Ce dossier va contenir d’autres dossiers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 N'oubliez pas d'exclure ce dossier de vos outils de build ou autres.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Par exemple, un dossier &lt;code&gt;eslint&lt;/code&gt;, qui contiendra un fichier où vous expliquerez pourquoi vous avez utilisé certains plugins eslint et pourquoi vous avez désactivé ou ajouté certaines règles de lint. Bien sûr, n'oubliez pas d'ajouter les dates.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Il est important que toutes les modifications de règles renvoient à la documentation de la règle ou du plugin.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Voici un exemple de fichier :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddfg9rx38uv8now5i7rm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddfg9rx38uv8now5i7rm.png" alt="Exemple de doc sur un projet" width="800" height="579"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quelques linters pour vous lancer
&lt;/h2&gt;

&lt;p&gt;Voici une liste de linters pour vous lancer avec le langage ou le format du fichier :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Langage&lt;/th&gt;
&lt;th&gt;Linter&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;JS/TS&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://eslint.org/" rel="noopener noreferrer"&gt;eslint&lt;/a&gt;, &lt;a href="https://biomejs.dev/" rel="noopener noreferrer"&gt;Biome&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;&lt;a href="https://checkstyle.sourceforge.io/" rel="noopener noreferrer"&gt;checkstyle&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;&lt;a href="https://golangci-lint.run/" rel="noopener noreferrer"&gt;GolangCi-lint&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/rust-lang/rust-clippy?tab=readme-ov-file#clippy" rel="noopener noreferrer"&gt;Clippy&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yaml&lt;/td&gt;
&lt;td&gt;&lt;a href="https://yamllint.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;Yamllint&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenApi&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.stoplight.io/docs/spectral/674b27b261c3c-overview" rel="noopener noreferrer"&gt;Spectral&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Si vous recherchez un linter pour votre langage ou un format de fichier, je vous conseille de regarder sur &lt;a href="https://megalinter.io/latest/" rel="noopener noreferrer"&gt;Megalinter&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Voilà j’espère vous avoir donné envie d’utiliser un linter ou des pistes pour améliorer votre expérience avec les linters 🐵&lt;/p&gt;

</description>
      <category>french</category>
      <category>productivity</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Tips&amp;Tricks pour améliorer votre CI/CD</title>
      <dc:creator>Jérémy Chauvin</dc:creator>
      <pubDate>Tue, 10 Oct 2023 19:45:11 +0000</pubDate>
      <link>https://forem.com/singebob/tipstricks-pour-ameliorer-votre-cicd-334k</link>
      <guid>https://forem.com/singebob/tipstricks-pour-ameliorer-votre-cicd-334k</guid>
      <description>&lt;p&gt;On a tous déjà ressenti de la frustration envers la pipeline du projet. Parce que la CI est trop lente ou encore elle nous sort des &lt;a href="https://www.jetbrains.com/fr-fr/teamcity/ci-cd-guide/concepts/flaky-tests/" rel="noopener noreferrer"&gt;tests flaky&lt;/a&gt; et il faut la relancer plusieurs fois pour que ça passe… Tout cela, fait que nous perdons beaucoup de temps avec quelque chose qui est censée nous aider et nous en faire gagner.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Au niveau de chaque point je vais mettre un ou plusieurs icônes pour indiquer le but de ce point :&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Icône&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🏎️&lt;/td&gt;
&lt;td&gt;Permet de gagner du temps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⭐&lt;/td&gt;
&lt;td&gt;Important de l’avoir ou de le faire&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Avant de vous parler d’astuce pour améliorer votre pipeline nous devons quand même qualifier le terme CI et CD.&lt;/p&gt;

&lt;h2&gt;
  
  
  Définition CI/CD
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Intégration Continue (Continuous Integration)
&lt;/h3&gt;

&lt;p&gt;L’intégration continue est une &lt;strong&gt;pratique&lt;/strong&gt; consistant à exécuter différents &lt;strong&gt;contrôles&lt;/strong&gt; sur tout type de contribution à votre repo.&lt;/p&gt;

&lt;p&gt;Nous allons souvent rencontrer ces étapes-là :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build image ou du binaire&lt;/li&gt;
&lt;li&gt;Test&lt;/li&gt;
&lt;li&gt;Lint&lt;/li&gt;
&lt;li&gt;Scan de vulnérabilités&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Déploiement Continu (Continuous Deployment)
&lt;/h3&gt;

&lt;p&gt;Le déploiement continu est la &lt;strong&gt;pratique&lt;/strong&gt; qui consiste à déployer &lt;strong&gt;automatiquement&lt;/strong&gt; des nouvelles versions dans un environnement dédié.&lt;/p&gt;

&lt;p&gt;Nous allons souvent rencontrer ces étapes là :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Déploiement de l’image&lt;/li&gt;
&lt;li&gt;Génération de la release note&lt;/li&gt;
&lt;li&gt;Génération de la version (tag, release, etc)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏎️ Mise en place de cache de dépendance
&lt;/h2&gt;

&lt;p&gt;Une des premières étapes de la CI consiste à télécharger les dépendances du projet pour pouvoir exécuter les tests ou faire le build. Bref, c’est une étape essentielle pour votre CI. &lt;/p&gt;

&lt;p&gt;Cette étape, qui est majeure pour votre CI, prend un certain temps. Plus le projet est gros plus ce temps est important. Il est donc primordial de mettre en place un cache pour gagner du temps. &lt;/p&gt;

&lt;p&gt;Il y a quand même plusieurs types de cache de dépendances :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;on peut voir le cache de dépendance de &lt;em&gt;pnpm&lt;/em&gt; et &lt;em&gt;maven&lt;/em&gt; qui consiste à faire un dossier au niveau du user où il ne font simplement qu’un lien symbolique ou une copie dans le projet.&lt;/li&gt;
&lt;li&gt;Le deuxième cache consiste à prendre votre fichier de gestion dépendance (exemples : package-lock.json (npm en JS, TS), poetry.lock (poetry en python) …) et de le hasher. Ce qui va vous générer un code unique en fonction du contenu du fichier. Si vous avez une nouvelle dépendance ou une nouvelle version d’une dépendance alors le hash sera différent. Une fois le hash calculé, vous pouvez créer un lien symbolique entre votre dossier du hash et le dossier qui contient les dépendances.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Comment on fait ? 💡
&lt;/h3&gt;

&lt;p&gt;Pour la plupart des outils de CI connus, vous pouvez définir une gestion de cache à partir d’un ou plusieurs fichier comme clé.&lt;/p&gt;

&lt;p&gt;Par exemple :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.gitlab.com/ee/ci/caching/#cache-nodejs-dependencies" rel="noopener noreferrer"&gt;Gitlab CI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/actions/setup-node#caching-global-packages-data" rel="noopener noreferrer"&gt;Github Action&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://circleci.com/blog/config-best-practices-dependency-caching/" rel="noopener noreferrer"&gt;Circle CI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ⭐ 🏎️ Paralléliser un maximum
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Paralléliser vos stages/job dans votre CI ou votre CD.
&lt;/h3&gt;

&lt;p&gt;Vous devez paralleliser un maximum vos étapes pour gagner du temps. C’est simple dit comme ça, mais il faut y penser. On a tendance à faire beaucoup de synchronisme même dans nos étapes de pipelines, alors que nous pouvons simplement les paralleliser.&lt;/p&gt;

&lt;p&gt;Nous pouvons prendre l’exemple du CI qui ne va faire que le build, le test et un lint. Dans environ 80% des CI qui existent nous allons retrouver ça :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Le build en premier&lt;/li&gt;
&lt;li&gt;Les tests qui dépendent du build (si le build échoue, on ne lance pas les tests)&lt;/li&gt;
&lt;li&gt;La tache de lint qui dépend des tests (si les tests fail on ne lance pas le lint)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpgovu89pe5ym1cp7amln.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpgovu89pe5ym1cp7amln.png" alt="CI sans Paralléliser" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La liaison entre le build et les tests peut exister pour les langages compilés. Par contre pour les langages interprétés du type JS, python etc, vous n’avez pas besoin d’attendre la fin du build pour exécuter vos tests.&lt;/p&gt;

&lt;p&gt;La liaison entre votre linter et vos tests (ou même implicitement votre build) n’a AUCUNE raison d’exister. Cette tâche peut être lancée en même temps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvibu1bkk93uqamkjoia1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvibu1bkk93uqamkjoia1.png" alt="CI Paralléliser" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Paralléliser vos tests
&lt;/h3&gt;

&lt;p&gt;Comme vous pouvez paralléliser vos jobs ou vos stages dans votre CI, vous pouvez tout aussi bien paralléliser vos tests en utilisant, par exemple, des test runners spécialement conçus à cet effet, tels que &lt;a href="https://github.com/avajs/ava" rel="noopener noreferrer"&gt;AvA&lt;/a&gt; en JS/TS.&lt;/p&gt;

&lt;p&gt;Avoir une étape de test dans votre CI ne veut pas dire que c’est un fourretout. Vous pouvez créer plusieurs étapes qui peuvent tourner en même temps. Comme par exemple avoir une étape de test unitaire, test d’intégration, etc&lt;/p&gt;

&lt;p&gt;On va être un peu plus précis pour les tests d'intégration qui sont complexes. Surtout sur la gestion de la base de données et des données qui y sont contenues. &lt;/p&gt;

&lt;p&gt;Premièrement, il incombe aux tests de lancer la base de données et de mettre en place les données nécessaires pour les tests.&lt;/p&gt;

&lt;p&gt;Deuxièmement, votre base de données n'est pas obligée d'être vidée et de réinsérer des données. Vous pouvez simplement, vous assurer que vos tests ne s'entremêlent pas en utilisant des données un peu plus aléatoires, comme par exemple des UUID au lieu d'auto-incrément, ce qui réduit les chances que les données entrent en collision si vous effectuez une insertion dans votre test.&lt;/p&gt;

&lt;p&gt;Troisièmement, sur des tests d’intégration je vous déconseille de vérifier des données avec des valeurs absolues mais de bien les vérifier à partir d’un objet généré avec des données générées. &lt;/p&gt;

&lt;p&gt;Une fois que vous avez fait tout ça, vous pouvez normalement les parralléliser simplement 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  ⭐ ⭐ Avoir les bonnes dimensions de machines
&lt;/h2&gt;

&lt;p&gt;Il est également très important de bien choisir les ressources que vous accordez à vos runners de votre pipeline.&lt;/p&gt;

&lt;p&gt;Si vos runners n'ont pas les ressources minimales pour exécuter certains logiciels, tels que Cypress ou d'autres outils qui peuvent être gourmands en ressources, vous vous retrouverez avec une étape lente ou, pire encore, une étape qui plante et qui va sortir des faux positifs.&lt;/p&gt;

&lt;p&gt;Ce qu'il y a de plus frustrant pour vos utilisateurs c’est de devoir relancer certains jobs et d'espérer que ça passe. Ils perdent beaucoup de temps et s'ils se produisent fréquemment, ils peuvent décider de supprimer ou de passer le test qui est en faux positif afin de contourner le problème.&lt;/p&gt;

&lt;h2&gt;
  
  
  🏎️ 🏎️ Ne pas reproduire deux fois la même chose
&lt;/h2&gt;

&lt;p&gt;Je pense que cette étape est une étape qui peut vous faire gagner beaucoup de temps. Imaginons que nous soyons sur un projet qui utilise le git flow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrggptarcwg1ctqpwkja.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrggptarcwg1ctqpwkja.png" alt="Git Flow" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pour les branches de feature, nous n'exécutons que les étapes de notre CI, c'est-à-dire Build, Test et Lint. La CI met en tout 5 minutes à tourner. Lorsque la branche de feature est mergée ou rebasée sur votre branche de develop, la CI retourne également, tout comme lorsque vous arrivez sur votre branche de release. Cela signifie que pour le même commit, donc le même code, nous exécutons la CI 3 fois, ce qui nous donne exactement le même résultat. L'utilisateur doit attendre 5 minutes sur develop avant de pouvoir le déployer sur son environnement, et c'est la même chose sur sa branche de release.&lt;/p&gt;

&lt;p&gt;Pour éviter que votre utilisateur ne perde encore plus de temps sur votre pipeline, il y a une solution. Vous pouvez faire la promotion de l'artifact, c'est-à-dire que votre artifact sera créé sur votre branche de feature, en utilisant l'identifiant de votre commit comme identifiant de votre artifact.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Exemple de votre artefact :&lt;br&gt;
&lt;code&gt;application-0de83a78334c64250b18b5191f6cbd6b97e77f84&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Le nom de votre artefact peut être plus court si vous utilisez la version courte de l'ID du commit :&lt;br&gt;
&lt;code&gt;application-0de83a7&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Mais vous pouvez aussi le combiner avec le futur numéro de version :&lt;br&gt;
&lt;code&gt;application-2.3.1-0de83a7&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dès que votre artefact est prêt, la première étape de votre CI sera de vérifier si l'artefact existe afin de sauter toute la partie CI et passer directement à votre CD sans attendre.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Vous pouvez aussi le faire si vous faites du trunk based 😁&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ⭐ 🏎️ Lancer vos stages/jobs que quand c’est utile
&lt;/h2&gt;

&lt;p&gt;Imaginons que dans votre projet, vous ayez vos fichiers de configuration de déploiement kubernetes, pour l’exemple on va parler de fichier helm. Ce qui nous donne ceci :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4flajxzu14i12vbd199.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4flajxzu14i12vbd199.png" alt="Image description" width="194" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lorsque vous modifiez uniquement les fichiers du dossier Helm, vous ne devez pas lancer toute la CI du projet. Vous ne devez lancer que la CI de ce dossier en particulier, par exemple un linter pour YAML ou le linter de Helm. De même, si le fichier n'a pas été modifié, vous n'avez pas besoin de lancer la CI de ce dossier. Ce qui signifie pas de tâche de linter Helm ou YAML pour ce dossier.&lt;/p&gt;

&lt;p&gt;Si vous suivez cette étape correctement, vous ou vos utilisateurs pourrez faire de petites modifications de configuration sans perdre de temps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comment on fait ? 💡
&lt;/h3&gt;

&lt;p&gt;Pour la plupart des outils de CI connus, vous pouvez définir des conditions sur le &lt;strong&gt;quand&lt;/strong&gt; lancer vos étapes/jobs. Et dans ces conditions, il y a la possibilité de choisir si un dossier ou un fichier a été modifié.&lt;/p&gt;

&lt;p&gt;Par exemple :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.gitlab.com/ee/ci/yaml/index.html#ruleschanges" rel="noopener noreferrer"&gt;Gitlab CI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dorny/paths-filter#example" rel="noopener noreferrer"&gt;Github Action&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://circleci.com/developer/orbs/orb/circleci/path-filtering" rel="noopener noreferrer"&gt;Circle CI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ⭐ ⭐ ⭐ Définir une durée maximum au niveau de votre pipeline
&lt;/h2&gt;

&lt;p&gt;Ce tips est, pour moi, un des trois plus important de votre pipeline, il va vous permettre de ne pas (re)tomber dans une pipeline qui dure plus de 20 minutes ou plus.&lt;/p&gt;

&lt;p&gt;On va parler de la &lt;a href="https://fr.wikipedia.org/wiki/Loi_de_Parkinson" rel="noopener noreferrer"&gt;loi de Parkinson&lt;/a&gt;, qui nous apprend que le temps du travail a tendance à s'étendre pour occuper tout le temps disponible pour sa réalisation. En d'autres termes, si vous accordez une certaine quantité de temps pour accomplir une tâche (même si elle pourrait être terminée plus rapidement) elle prendra souvent tout le temps alloué.&lt;/p&gt;

&lt;p&gt;Il est donc très important de fixer une durée maximale pour votre CI/CD et également pour vos étapes le plus tôt possible. Car si vous ne le faites pas, le temps va continuer à s'étirer jusqu'à atteindre un point où il devient très compliqué et coûteux de revenir à un environnement stable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comment on fait ? 💡
&lt;/h3&gt;

&lt;p&gt;Pour la plupart des outils de CI connus, vous pouvez définir un timeout par job ou steps.&lt;/p&gt;

&lt;p&gt;Par exemple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.gitlab.com/ee/ci/pipelines/settings.html#set-a-limit-for-how-long-jobs-can-run" rel="noopener noreferrer"&gt;Gitlab CI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepstimeout-minutes" rel="noopener noreferrer"&gt;Github Action&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.circleci.com/hc/en-us/articles/4411204604059-Automatically-cancel-build-after-set-amount-of-time" rel="noopener noreferrer"&gt;Circle CI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ⭐ ⭐ ⭐ Mise en place d’alerting
&lt;/h2&gt;

&lt;p&gt;Comme le précédent tips, je le considère comme très important et pas seulement pour votre pipeline mais pour tout software.&lt;/p&gt;

&lt;p&gt;La mise en place d'un système d'alerte robuste dans votre CI/CD est d'une importance capitale pour garantir la réactivité et la fiabilité de vos opérations de développement et de déploiement. L'alerting permet de surveiller en temps réel chaque étape de votre pipeline CI/CD, identifiant ainsi toute anomalie, tout retard ou tout échec potentiel. En recevant des alertes immédiates lorsqu'un problème survient, l'équipe peut intervenir rapidement pour diagnostiquer, résoudre et rétablir la stabilité du pipeline. Cela réduit considérablement les temps d'arrêt, optimise le temps de réaction et contribue à maintenir la fluidité et l'efficacité de la chaîne de livraison logicielle.&lt;/p&gt;

&lt;p&gt;De plus, l'alerting dans la CI/CD favorise une culture de responsabilité et d'amélioration continue au sein de l'équipe de développement. En recevant des alertes en temps réel, chaque membre de l'équipe est informé de l'état du pipeline et de tout incident potentiel. Cela encourage une réactivité immédiate et incite les membres de l'équipe à résoudre les problèmes rapidement et efficacement. De plus, ces alertes fournissent des données exploitables pour effectuer des analyses post-mortem, identifier les problèmes récurrents et itérer constamment le processus afin d'améliorer la robustesse et l'efficacité de la CI/CD. En fin de compte, l'alerting sert non seulement à maintenir des opérations fluides, mais aussi à stimuler l'innovation et l'efficacité de l'équipe de développement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comment on fait ? 💡
&lt;/h3&gt;

&lt;p&gt;Pour la plupart des outils de CI connus, vous pouvez récupérer les métriques et les utiliser dans un dashboard datadog ou autre&lt;/p&gt;

&lt;p&gt;Par exemple :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.datadoghq.com/blog/monitor-gitlab-with-datadog/" rel="noopener noreferrer"&gt;Gitlab CI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.datadoghq.com/blog/datadog-github-actions-ci-visibility/" rel="noopener noreferrer"&gt;Github Action&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Circle CI :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Circle CI ont leur propre solution de monitoring&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://circleci.com/docs/insights/" rel="noopener noreferrer"&gt;Voir les métriques&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://circleci.com/docs/notifications/#notifications-with-orbs" rel="noopener noreferrer"&gt;Envoyer des notifications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Voilà j’espère vous avoir donner des idées pour améliorer votre pipeline de CI/CD 🐵&lt;/p&gt;

</description>
      <category>french</category>
      <category>cicd</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Différentes façons de déployer une application front faites en JS</title>
      <dc:creator>Jérémy Chauvin</dc:creator>
      <pubDate>Wed, 12 Jul 2023 17:18:19 +0000</pubDate>
      <link>https://forem.com/singebob/differentes-facons-de-deployer-une-application-front-faites-en-js-13of</link>
      <guid>https://forem.com/singebob/differentes-facons-de-deployer-une-application-front-faites-en-js-13of</guid>
      <description>&lt;p&gt;Nous avons tous déjà vécu l'expérience de travailler sur un side Project, de coder l'ensemble de l'application, puis de se demander : « Comment vais-je le déployer ? ». &lt;/p&gt;

&lt;p&gt;Dans cet article, vous allez (re)découvrir les différentes façons de déployer votre application front, ainsi que les cas où il est plus intéressant d'utiliser telle ou telle méthode.&lt;/p&gt;

&lt;p&gt;Mais avant de parler de déploiement, il faut expliquer les différentes implémentations d'application que vous pouvez rencontrer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plusieurs implémentations d’application front JS
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Ici on va expliquer grossièrement les différences entre les plusieurs types d’implémentations, car certains déploiements ne peuvent être fait avec certaines implémentations&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;SPA ( Single Page Application )&lt;/p&gt;

&lt;p&gt;Ce genre d'implémentation est vraiment simple. Elle est composée d’un fichier HTML qui fait référence à un fichier JS (aussi appelé &lt;em&gt;bundle&lt;/em&gt;). Ce &lt;em&gt;bundle&lt;/em&gt; permet de charger tout le contenu de la page côté client.&lt;/p&gt;

&lt;p&gt;Lorsque vous exécutez votre commande de build pour votre application, vous obtenez:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;index.html&lt;/li&gt;
&lt;li&gt;script.js (un &lt;em&gt;bundle&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;public (un dossier contenant des images et le favicon du site)&lt;/li&gt;
&lt;li&gt;style.css (un &lt;em&gt;bundle&lt;/em&gt; de votre CSS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ce genre d'implémentation est souvent utilisé dans les nouvelles librairies front telles que &lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;React&lt;/a&gt;, &lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;Vue&lt;/a&gt;, &lt;a href="https://angular.io/" rel="noopener noreferrer"&gt;Angular&lt;/a&gt; ou &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; (et sûrement d'autres).&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;SSG ( Static Site Generator )&lt;/p&gt;

&lt;p&gt;Cette implémentation permet de générer des pages HTML statiques à partir de fichiers sources, tels que des fichiers Markdown. Le SSG est très souvent utilisé pour créer des blogs ou des sites vitrines.&lt;/p&gt;

&lt;p&gt;Pour savoir si vous utilisez un SSG, c'est assez facile. Lorsque vous allez construire votre application, dans votre sortie vous allez voir votre structure de fichier être transformée en fichier HTML, par exemple :&lt;/p&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dg02503psbc1841wsqs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dg02503psbc1841wsqs.png" alt="Image description" width="432" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28jtimf93ingz0uzq018.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28jtimf93ingz0uzq018.png" alt="Image description" width="442" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Les bibliothèques/frameworks qui existent pour faire du SSG : &lt;a href="https://www.gitbook.com/" rel="noopener noreferrer"&gt;GitBook&lt;/a&gt;, &lt;a href="https://docusaurus.io/fr/" rel="noopener noreferrer"&gt;Docusaurus&lt;/a&gt;, &lt;a href="https://vitepress.dev/" rel="noopener noreferrer"&gt;Vitepress&lt;/a&gt;, &lt;a href="https://starlight.astro.build/" rel="noopener noreferrer"&gt;Starlight&lt;/a&gt;, &lt;a href="https://iles.pages.dev/" rel="noopener noreferrer"&gt;îles&lt;/a&gt; et pleins d'autres.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;SSR ( Server Side Rendering )&lt;/p&gt;

&lt;p&gt;Cette implémentation permet de générer le rendu HTML côté serveur, comme en PHP ou en Java avec les JSP, et de n'envoyer que le strict minimum à l'utilisateur.&lt;/p&gt;

&lt;p&gt;Pour savoir si vous utilisez cette méthode d'implémentation, il faut consulter la documentation de votre framework ou de vos bibliothèques. Il n'y a pas de manière simple de le savoir.&lt;/p&gt;

&lt;p&gt;Parmi les frameworks qui proposent du SSR, on retrouve &lt;a href="https://astro.build/" rel="noopener noreferrer"&gt;Astro&lt;/a&gt;, &lt;a href="https://kit.svelte.dev/" rel="noopener noreferrer"&gt;SvelteKit&lt;/a&gt;, &lt;a href="https://nuxt.com/" rel="noopener noreferrer"&gt;Nuxt&lt;/a&gt;, &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next&lt;/a&gt; et d'autres.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Différentes façons de déployer une application front
&lt;/h1&gt;

&lt;p&gt;Lorsqu'il s'agit de déployer une application front, il existe plusieurs méthodes à considérer. Voici les façons les plus courantes de le faire :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 J’ai mis en place un tableau dans les méthodes de déploiement pour savoir si elles sont adaptées en fonction de l’implémentation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Voici la légende du tableau: &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pastille de couleurs&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🌟&lt;/td&gt;
&lt;td&gt;Solution Idéale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Solution fonctionnelle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Impossible&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Utilisation de bucket/S3
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Implémentation front&lt;/th&gt;
&lt;th&gt;Possible ?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SPA&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSG&lt;/td&gt;
&lt;td&gt;🌟&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSR&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Vous pouvez utiliser un service de stockage de fichiers (bucket) ou S3 pour héberger votre site web, mais cela n'est possible que pour les applications de type SSG et SPA. Il est impossible de déployer une application SSR sur un bucket car il n'y a pas de serveur node qui permet de générer les pages HTML.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Attention pour les SPA, si vous les déployez sur un bucket/S3, vous devez mettre l’&lt;em&gt;index.html&lt;/em&gt; en entrée par défaut et en entrée si le fichier n’est pas trouvé dans votre bucket. Par exemple, vous avez une route nommer &lt;em&gt;/blog&lt;/em&gt; votre bucket va chercher un fichier nommée &lt;em&gt;blog.html&lt;/em&gt; à la racine. Mais comme dit plus haut pour les SPA, il n’existe que votre fichier index.html&lt;/p&gt;

&lt;p&gt;⚠️ Un déploiement avec un bucket/S3 sera en HTTP. La redirection DNS suffit pour avoir votre site en HTTPS, mais il y a quand même un risque de sécurité. AWS à leur propre solution pour passer l’URL de votre S3 en HTTPS&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Les avantages :
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Facile à mettre en place ( peu de connaissance technique pour le mettre en place )&lt;/li&gt;
&lt;li&gt;Évite les coûts et les contraintes d'un serveur&lt;/li&gt;
&lt;li&gt;Haute dispo &amp;amp; scalabilité&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Les désavantages:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Peut vite devenir cher, si vous avez beaucoup de visites&lt;/li&gt;
&lt;li&gt;Zéro contrôle sur l’environnement, vous ne pouvez seulement specifier le fichier d’entrées et le fichier si aucun fichier n’est trouvé&lt;/li&gt;
&lt;li&gt;Très peu sécurisés, tout les fichiers dans les buckets sont accessibles&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cas d’utilisation intéressant:
&lt;/h3&gt;

&lt;p&gt;Le cas d’utilisation intéressant pour ce type de déploiement est :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;les sites statiques ( blog, landing page )&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Utilisation de services de PaaS ( Plateforme as a Service )
&lt;/h2&gt;

&lt;p&gt;Les services de PaaS tels que &lt;a href="https://www.netlify.com/" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt;, &lt;a href="https://vercel.com/" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt; ou encore &lt;a href="https://www.clever-cloud.com/" rel="noopener noreferrer"&gt;Clever Cloud&lt;/a&gt; sont des plateformes de déploiement qui permettent de déployer rapidement des applications. Ces services prennent en charge la génération de sites statiques mais depuis peu les implémentations dynamiques comme le SSR.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Implémentation front&lt;/th&gt;
&lt;th&gt;Possible ?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SPA&lt;/td&gt;
&lt;td&gt;🌟&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSG&lt;/td&gt;
&lt;td&gt;🌟&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSR&lt;/td&gt;
&lt;td&gt;🌟&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Avantages :
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Facile à mettre en place ( peu de connaissance technique pour le mettre en place )&lt;/li&gt;
&lt;li&gt;Évite les coûts et les contraintes d'un serveur&lt;/li&gt;
&lt;li&gt;La version gratuite peut-être suffisant au début&lt;/li&gt;
&lt;li&gt;Beaucoup de feature intéressante, comme les environnements générés sur chaque PR&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Désavantages :
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Coût mensuel ou annuel pour l'utilisation de la plateforme&lt;/li&gt;
&lt;li&gt;Limitations de personnalisation et de configuration&lt;/li&gt;
&lt;li&gt;Dépendance à un tiers pour le déploiement et l'hébergement ( Un peu vrai pour tous les services cloud )&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cas d’utilisation intéressant:
&lt;/h3&gt;

&lt;p&gt;Le cas d’utilisation intéressant pour ce type de déploiement est :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Le début d’un side projet pour livrer le plus rapidement possible de la valeurs sans se prendre la tête&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Utilisation d’un service CaaS ( Container as a service )
&lt;/h2&gt;

&lt;p&gt;Vous pouvez aussi déployer votre application sous forme de containers. Pour ce faire, vous devez créer une image, avec un dockerfile ou encore en passant par &lt;a href="https://buildpacks.io/" rel="noopener noreferrer"&gt;buildpack&lt;/a&gt;. Une fois votre image créée et mise sur une registry accessible, vous pouvez la deployer via des services cloud comme GCP, AWS, Azure, Scaleway voir même sur certains services de PaaS comme Clever Cloud&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Implémentation front&lt;/th&gt;
&lt;th&gt;Possible ?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SPA&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSG&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSR&lt;/td&gt;
&lt;td&gt;🌟&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Avantages :
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Possibilité de déployer sur de multiples environnements assez facilement&lt;/li&gt;
&lt;li&gt;Possibilité de personnaliser le déploiement et la configuration de l'environnement&lt;/li&gt;
&lt;li&gt;Possibilité de gérer efficacement les ressources et de réduire les coûts&lt;/li&gt;
&lt;li&gt;Possibilité de mettre en place des stratégies de scalabilité horizontales&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Désavantages :
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Nécessite des compétences techniques et une certaine expertise pour mettre en place et gérer l'environnement de déploiement&lt;/li&gt;
&lt;li&gt;Coûts associés à l'utilisation de services cloud pour héberger l'application&lt;/li&gt;
&lt;li&gt;Complexité accrue par rapport à d'autres méthodes de déploiement plus simples&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cas d’utilisation intéressant:
&lt;/h3&gt;

&lt;p&gt;Le cas d’utilisation intéressant pour ce type de déploiement est :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Si vous êtes en entreprise et qu’il y a déjà un cluster kube pour déployer vos applications et qu’on vous interdit d’utiliser un PaaS&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Utilisation d’un Serveur ou VM dédié
&lt;/h2&gt;

&lt;p&gt;Vous pouvez aussi déployer vos applications front depuis un serveur dédié ou une VM. Pour ce faire, il suffit de mettre en place un reverse proxy comme Nginx, Traefik, HaProxy et certainement d’autres.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Si vous voulez déployer du SSR sur un serveur dédié, il faut penser à mettre en place un serveur node, si vous faites du Next, Nuxt ou SvelteKit. Si vous faites du PHP, n’oubliez pas d’en mettre un aussi sinon ça ne va pas fonctionner.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6t84uqp31gkuur3qy0c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6t84uqp31gkuur3qy0c.png" alt="Image description" width="432" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Implémentation front&lt;/th&gt;
&lt;th&gt;Possible ?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SPA&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSG&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSR&lt;/td&gt;
&lt;td&gt;🌟&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Avantages :
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Possibilité de personnaliser le déploiement&lt;/li&gt;
&lt;li&gt;Contrôle total sur l'environnement de l'application&lt;/li&gt;
&lt;li&gt;Pas de coûts supplémentaires pour l'utilisation d'une plateforme tierce&lt;/li&gt;
&lt;li&gt;Possibilité d'ajouter des modules et des bibliothèques personnalisées&lt;/li&gt;
&lt;li&gt;Possibilité de gérer les ressources et de réduire les coûts&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Désavantages :
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Nécessite des compétences techniques et une certaine expertise pour la mise en place et la gestion de l'environnement de déploiement&lt;/li&gt;
&lt;li&gt;Complexité accrue par rapport à d'autres méthodes de déploiement plus simples&lt;/li&gt;
&lt;li&gt;Risques de sécurité plus élevés en cas d'erreurs de configuration&lt;/li&gt;
&lt;li&gt;Nécessite une maintenance régulière pour garantir la sécurité et les performances de l'application&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cas d’utilisation intéressant:
&lt;/h3&gt;

&lt;p&gt;Le cas d’utilisation intéressant pour ce type de déploiement est :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pour apprendre la complexité de deployer et de maintenir un serveur web soi-même&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tableau récapitulatif
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;SPA&lt;/th&gt;
&lt;th&gt;SSG&lt;/th&gt;
&lt;th&gt;SSR&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bucket/S3&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🌟&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PaaS&lt;/td&gt;
&lt;td&gt;🌟&lt;/td&gt;
&lt;td&gt;🌟&lt;/td&gt;
&lt;td&gt;🌟&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CaaS&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🌟&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serveur ou VM dédié&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;🌟&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Il existe beaucoup moyen de déployer une application front, mais chaque façon de déployer a des avantages comme des inconvénients. Il est donc important de le savoir, par contre ce choix ne doit pas vous bloquer. Vous pouvez logiquement le changer sans problèmes.&lt;/p&gt;

&lt;p&gt;Voilà j’espère vous avoir donner des idées pour déployer votre application front que ça soit votre blog ou vos sides projects 🐵&lt;/p&gt;

</description>
      <category>french</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
