> ## Content Index
> Fetch the complete content index at: https://www.sfeir.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# Soirée quiz dans le terminal avec Enquirer
- URL: https://www.sfeir.dev/back/soiree-quiz-dans-le-terminal-avec-enquirer/
- Published: 2023-08-10T07:51:04.000Z
- Updated: 2023-11-11T14:54:29.000Z
- Description: Passons de la théorie à la pratique en créant votre propre quiz dans le terminal.
- Author: Alexandre Moevi
- Tags: Back, Node.js

*Dans un [précédent article](https://www.sfeir.dev/comment-sublimer-les-cli-avec-enquirer/), nous avons exploré les possibilités offertes par la bibliothèque Enquirer. Cet article fait suite à cette exploration initiale. Nous allons nous lancer dans la création d'un quiz interactif en ligne de commande.*

Avant toute chose, nous allons installer deux nouvelles dépendances en exécutant `npm install ansi-colors chalk@4.1.2`. À partir de la version 5, `chalk` est passé au format ESM (Modules ECMAScript). Puisque j'ai opté pour le CommonJS dans le premier article, je vais donc me contenter de la version 4\. Passer à ESM ? Peut-être une autre fois…

## Questions pour un dev !

Pour mettre en place notre quiz, nous allons utiliser la méthode `prompt` qui a l'avantage d'accepter une liste de questions, contrairement à la classe `Quiz`.

```javascript
const { prompt } = require("enquirer");

prompt([
    {
        type: "quiz",
        name: "countries",
        message: 'How many countries are there in the world?',
        choices: ['165', '175', '185', '195', '205'],
        correctChoice: 3
    },
    {
        type: "quiz",
        name: "math",
        message: 'What is 9 + 10?',
        choices: ['19', '20', '21'],
        correctChoice: 0
    }
]).then((answer) => console.log("Answer:", answer)).catch(console.error);

// Answer: {
//     countries: { selectedAnswer: '165', correctAnswer: '195', correct: false },
//     math: { selectedAnswer: '19', correctAnswer: '19', correct: true }
// }
```

quiz.cjs

Une question a besoin d'un `type` qui sera `quiz` puisqu'on veut créer un quiz, un `name`, un `message` qui est la question pour l'utilisateur, `choices` qui est une liste de propositions et enfin `correctChoice`, qui correspond à l'indice dans le tableau `choices` de la bonne réponse.

Si vous lancez le quiz dans le terminal avec `node quiz.cjs`, vous allez sans doute trouver les contrôles très rapidement : **`↑`** et **`↓`** pour naviguer parmi les propositions et `Entrée` pour valider votre choix. 

À la fin de toutes les questions, on récupère un objet avec pour chaque question le choix de l'utilisateur, la réponse attendue `correctAnswer` et un booléen indiquant si l'utilisateur a choisi la bonne réponse ou non.

Pour alimenter notre quiz avec des questions plus intéressantes, on va s'appuyer sur l'[API de l'Open Trivia Database](https://opentdb.com/api%5Fconfig.php?ref=sfeir.dev). Ce service est libre (pas besoin de clé d'API) et gratuit. On peut sélectionner le nombre de questions, le thème et la difficulté.

```javascript
const loadQuestions = async () => {
    const res = await fetch(TRIVIA_URL);
    if (res.ok) {
        const data = await res.json();
        const questions = data.results.map((question, index) => {
            const choices = [...question.incorrect_answers, question.correct_answer];
            choices.sort(() => Math.random() - 0.5);
            return {
                type: "quiz",
                name: `Question ${index + 1}`,
                message: question.question,
                choices,
                correctChoice: choices.indexOf(question.correct_answer)
            }
        })
        return questions
    }
};
```

quiz.cjs

La méthode ci-dessus va récupérer des questions à partir d'Open Trivia Database et les transformer au format attendu par Enquirer. Pour éviter d'avoir la réponse toujours au même endroit dans la liste des propositions, je rajoute un peu d'aléatoire avec `Math.random()`.

Maintenant que nous avons des questions plus variées et au bon format, nous pouvons les soumettre au prompt.

```javascript
const runQuiz = async () => {
    const questions = await loadQuestions();
    const answers = await prompt(questions);
}

runQuiz().catch(console.error)
```

quiz.cjs

Comme nous avons vu plutôt, `answers` est un objet dont les clés sont les noms des questions et les valeurs le résultat. Comme sortie finale, nous allons afficher le score ainsi que les réponses incorrectes afin que le joueur dorme moins bête cette nuit. 

On va importer les modules `ansi-colors` et `chalk` pour l'affichage du score. En itérant sur les réponses à la fin du questionnaire, on incrémente le `score` quand la réponse est correcte et on donne la correction dans le cas contraire.

```javascript
const { green, red } = require('ansi-colors');
const { bold, strikethrough } = require('chalk');

const runQuiz = async () => {
    let score = 0;
    const questions = await loadQuestions();
    const answers = await prompt(questions);
    Object.entries(answers).forEach(([questionName, result]) => {
        if(result.correct) {
            score++;
        } else {
            console.log(`${questionName} : ${strikethrough(red(result.selectedAnswer))} ${green(result.correctAnswer)}`);
        }
    });
    console.log(`${bold("Score")} : ${score}/${questions.length}`);
}

runQuiz().catch(console.error)
```

quiz.cjs

Voici ce que donne notre quiz dans mon terminal.

![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2023/08/image-6.png)

![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2023/08/image-7.png)

![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2023/08/image-5.png)

Sur la première image, la liste des propositions pour une question. Sur la deuxième image, le résultat à la fin du questionnaire. Sur la troisième et dernière image, un quiz où une mauvaise réponse a été choisie. On affiche la réponse qui était attendue.

## De nouveaux défis

Nous avons réussi à coder un quiz interactif et fonctionnel ! Cependant, il y a encore de la place à l'innovation et à l'optimisation. 

Par exemple, le point d'interrogation qui préfixe la question est systématiquement remplacé par une coche dès qu'une réponse est sélectionnée. Bien que cela indique que l'input de l'utilisateur a été reçu, cela pourrait prêter à confusion en suggérant que la réponse choisie est correcte, même si ce n'est pas le cas. 

De plus, pourquoi attendre la fin du questionnaire pour révéler les bonnes réponses ? Nous pourrions améliorer l'expérience utilisateur en remplaçant immédiatement les réponses sélectionnées en bleu par la correction en vert ou en rouge.

Si cela vous inspire, je vous laisse regarder comment ajouter la fonction `onSubmit()` dans les questions que l'on génère, voire [comment créer votre propre prompt](https://github.com/enquirer/enquirer/blob/master/docs/custom-prompts.md?ref=sfeir.dev) en héritant des classes `Quiz` ou `SelectPrompt`.

Et si le terminal n'est pas assez pour vous, et que vous aspirez à créer une interface graphique élégante et réactive, n'attendez pas à quai. Le train ViteJS est prêt au départ, et vous ne voudrez pas le manquer !

[ViteJS, ne ratez pas le train !ViteJS, dernier né de Evan You, est le bolide des outils de build front-end. Propulsant votre développement avec des fichiers servis à la demande et optimisé par Rollup en production, c’est le compagnon de route rêvé. ViteJS, c’est la promesse d’un développement web à grande vitesse.![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/size/w256h256/2023/03/AXO_GOOD-2.png)sfeir.devThomas SLOBODA![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2023/07/sawyer-bengtson-umRPY9w3q1c-unsplash.jpg)](https://www.sfeir.dev/front/vitejs-ne-ratez-pas-le-train/)

Ci-dessous, vous trouverez le code complet du fichier pour une consultation complète.

```javascript
const { prompt } = require("enquirer");
const { green, red } = require('ansi-colors');
const { bold, strikethrough } = require('chalk');
const TRIVIA_URL = ''; 		// URL à générer via l'Open Trivia DB

const loadQuestions = async () => {
    const res = await fetch(TRIVIA_URL);
    if (res.ok) {
        const data = await res.json();
        const questions = data.results.map((question, index) => {
            const choices = [...question.incorrect_answers, question.correct_answer];
            choices.sort(() => Math.random() - 0.5);
            return {
                type: "quiz",
                name: `Question ${index + 1}`,
                message: question.question,
                choices,
                correctChoice: choices.indexOf(question.correct_answer)
            }
        })
        return questions
    }
}

const runQuiz = async () => {
    let score = 0;
    const questions = await loadQuestions();
    const answers = await prompt(questions);
    Object.entries(answers).forEach(([questionName, result]) => {
        if(result.correct) {
            score++;
        } else {
            console.log(`${questionName} : ${strikethrough(red(result.selectedAnswer))} ${green(result.correctAnswer)}`);
        }
    });
    console.log(`${bold("Score")} : ${score}/${questions.length}`);
}

runQuiz().catch(console.error)
```

quiz.cjs