Partie utilisant Cursor et Claude pour créer des tests automatisés avec Playwright

Linda Hamilton
Libérer: 2024-11-06 01:54:02
original
178 Les gens l'ont consulté

Lien vers la partie 1

PARTIE 4

Voici le dépôt de code source Github pour ce projet : https://github.com/joegiglio/cursor2-kb

Ça faisait longtemps…

La dernière fois que nous avons parlé, le curseur semblait tomber en panne et l'index de la structure des fichiers était corrompu. Après avoir attendu 23 jours pour un correctif, je suis heureux d'annoncer que le problème semble enfin résolu ! L'interface utilisateur est toujours originale et semble ralentir après un certain temps avec une sorte de fuite de mémoire qui peut être corrigée avec un redémarrage. Mais au moins, il apporte désormais des modifications aux fichiers corrects et je ne suis pas confronté à un index de fichiers mystérieusement corrompu.

En attendant un correctif, j'ai remarqué que de nombreux utilisateurs de Cursor se plaignaient de l'instabilité de Cursor et/ou de Claude. Oui, cela fonctionne parfois et c'est impressionnant quand c'est le cas, mais c'est une boîte noire de pièces mobiles, de mises à jour constantes en coulisses et de résultats incohérents.

J'ai décidé de mettre le projet Help Desk de côté et je voulais voir si je pouvais plutôt créer une application de base de connaissances. Cela pourrait être un peu plus simple : pas besoin de mises à jour en temps réel ou de points d'intégration complexes.

J'ai utilisé la même pile technologique que celle que je connais le mieux - Python, Flask et Bootstrap avec une base de données SQLite. Tout se déroulait à merveille jusqu'à ce que je rencontre un problème avec les « migrations de bases de données ». Semblable au chapitre précédent, il a généré du code de contrainte que SQLite n'a pas aimé et a généré une erreur :

Exception during DB migration:
 raise ValueError("Constraint must have a name")
ValueError: Constraint must have a name
Copier après la connexion
Copier après la connexion

Cela aurait dû être assez facile à réparer pour Claude, mais cela a commencé à prendre une tournure vertigineuse et j'ai fini par reconstruire ma base de données à partir de zéro. Je blâmerai cela sur mon inexpérience en matière de débogage de flask-migrate, mais Claude n'a pas pu nettoyer le désordre sans simplement effacer la base de données et recommencer.

Part  Using Cursor and Claude to Create Automated Tests with Playwright

Une fois les choses réglées, je me suis retrouvé avec un système de base de connaissances essentiellement fonctionnel, avec un panneau d'administration, un mode sombre/clair, une recherche (en utilisant simplement les requêtes SQL) et un générateur de données de test. Il a été construit avec Quill, un éditeur de texte open source prenant en charge le formatage et les images.

Part  Using Cursor and Claude to Create Automated Tests with Playwright

Part  Using Cursor and Claude to Create Automated Tests with Playwright

Je dis « principalement fonctionnel » parce que je ne l’ai volontairement pas compliqué avec l’authentification ou la multi-location. J'ai gardé l'architecture simple avec des routes Flask de base et des opérations CRUD. Pas d'API pour l'instant… Peut-être que je revisiterai ces fonctionnalités dans la phase 2.

Au fur et à mesure que j'ajoutais des fonctionnalités, je remarquais que Claude réparait une chose mais en cassait une autre - tout comme un vrai développeur. De plus, il y avait du CSS et du Javascript dispersés partout dans le code. Parfois, l’ajout de nouveaux articles fonctionnerait mais l’édition ne fonctionnerait pas et vice versa. Parfois, du code de formatage d'article apparaissait ici et là et je devais demander à Claude de le nettoyer. Cela devenait dingue.

Le projet devenait suffisamment complexe pour nécessiter l'automatisation des tests, ce qui a été brièvement abordé dans le dernier chapitre. Dans la plupart des entreprises, il y a très peu de budget pour le QE et la plupart des développeurs détestent écrire des tests, alors peut-être que l'IA peut aider ?

J'ai une expérience respectable avec le sélénium et le concombre, mais cela fait un moment. Playwright gagne du terrain et est censé avoir une meilleure gestion des localisateurs et des tentatives, j'ai donc demandé à Claude de créer des tests Playwright. Les extensions VS-Code Playwright semblent toutes supposer que vous utilisez Javascript et elles ne prennent pas en charge directement Python, je devrai donc exécuter les tests depuis le terminal, comme un animal.

Part  Using Cursor and Claude to Create Automated Tests with Playwright

[INVITE]

Je voudrais ajouter des tests de navigateur de bout en bout à ce projet en utilisant Playwright et Python. J'aimerais que les tests utilisent des appareils pour amorcer les données nécessaires, puis suppriment les données à la fin de chaque exécution de test. Les tests doivent nettoyer après eux-mêmes et ne pas laisser de données de test derrière eux. Si vous pouvez le configurer pour configurer une base de données de test tout en exécutant les tests, c'est encore mieux. Veuillez me faire savoir quelles bibliothèques installer, créer des tests pour les 10 principaux scénarios en examinant les principales fonctionnalités du produit et dites-moi comment exécuter ces tests à partir de Cursor.

[/PROMPT]

La première tentative a été plutôt bonne, fournissant des instructions sur la façon d'installer les bibliothèques nécessaires. La structure des fichiers pour les tests semblait également précise et elle a même ajouté un test de réactivité en modifiant la taille de la fenêtre d'affichage. Belle touche… Mais je n'ai pas aimé la série initiale de tests qu'il a généré, alors je lui ai demandé un affinement supplémentaire :

[INVITE]

L'authentification n'a pas encore été implémentée dans ce produit. Veuillez ne pas créer de tests pour ces fonctionnalités. Concentrez-vous plutôt sur les fonctionnalités d'administration telles que la création, la modification et la suppression de sujets ; ajouter, modifier et supprimer des articles. Concentrez-vous également sur les fonctionnalités de l’utilisateur final telles que la recherche et la visualisation d’articles. Examinez le code pour découvrir les 10 principales fonctionnalités du produit et créez des tests pour elles.

[/PROMPT]

La prochaine série de tests semblait un peu meilleure mais toujours pas de fonctionnalité d'administration.

[INVITE]

La plupart de ces tests semblent plutôt bons, mais je ne vois rien concernant la fonctionnalité d'administration dans le fichier @admin.html. Nous avons besoin de tests pour ajouter, modifier, supprimer des sujets et ajouter, modifier et supprimer des articles.

[/PROMPT]

Il semble maintenant qu'il ait bien fait les choses et qu'il ait créé du code pour tester les scénarios d'application suivants :

Part  Using Cursor and Claude to Create Automated Tests with Playwright

Part  Using Cursor and Claude to Create Automated Tests with Playwright

Cela ressemble à d’excellents points de départ. Voyons maintenant si les instructions d'exécution de Claude sont correctes. Eh bien, malheureusement non…

[INVITE]

J'ai suivi vos instructions pour exécuter les tests et je rencontre quelques problèmes.
J'ai ouvert un nouveau terminal et exécuté les commandes « FLASK_ENV=testing flask run » suivies de « pytest tests/e2e/ ». Je vois les problèmes suivants :

  1. Lorsque j'accède à la page d'accueil, je vois les mêmes données que précédemment. Il ne semble pas passer à la base de données de test.
  2. Une exception : ImportError lors du chargement du concours '/Users/joe/cursor2-kb/tests/e2e/conftest.py'. tests/e2e/conftest.py:12 : dans le sujet d'importation de modèles, article ModuleNotFoundError : aucun module nommé 'modèles'

[/PROMPT]

Claude a créé un fichier models.py, dupliquant le code dans le fichier app.py et je me suis demandé pourquoi…

Le code initial de cette application a été entièrement réalisé dans le fichier app.py, y compris les modèles. Cela fonctionne bien mais peut vous laisser avec une application à fichier unique lourde. La meilleure pratique dit de séparer les modèles et les routes de la configuration et c'est là que Claude m'emmenait, même si cela a pris un chemin long et tortueux :

[INVITE]

Le fichier models.py que vous proposez semble dupliquer le code de app.py. Serait-il plus logique d'utiliser plutôt les modèles dans app.py ?

[/PROMPT]

[RÉPONSE]

En fait, c'est l'inverse : nous devrions déplacer les modèles de app.py vers models.py pour suivre le principe de séparation des préoccupations. Il s'agit d'un modèle courant dans les applications Flask où :
app.py gère la configuration et l'initialisation de l'application
models.py contient tous les modèles de base de données
les itinéraires sont souvent dans des fichiers de plans séparés

[/RÉPONSE]

Assez juste. Allons-y !

Eh bien, pas si vite. En y regardant de plus près…

[INVITE]

J'aime où vous allez en séparant le fichier models.py mais vous avez également supprimé toutes les routes du fichier app.py. Je ne les vois dans aucun autre fichier. Ils sont juste partis…

[/PROMPT]

Maintenant, Claude a extrait tous les itinéraires du fichier app.py et les a déplacés dans un fichier séparé pour les plans. Il apporte beaucoup trop de changements architecturaux et je veux qu'il revienne… Méfiez-vous du nouveau développeur brillant qui veut tout réécrire ! Bien que les modifications suggérées soient considérées comme les meilleures pratiques pour une base de code Flask professionnelle, je ne ferai pas confiance à ces modifications tant que les tests ne seront pas en place afin que nous puissions vérifier qu'ils fonctionnent correctement.

[INVITE]

Je comprends que l'utilisation de plans est la méthode préférée pour le code Flask de niveau professionnel. Cependant, je ne suis pas à l'aise pour faire de tels refactors pour le moment. J'essaie d'abord de mettre en place des tests de bout en bout. Ensuite, nous pouvons examiner la structure du projet. Veuillez ne pas déplacer les itinéraires hors du fichier app.py.

[/PROMPT]

Part  Using Cursor and Claude to Create Automated Tests with Playwright

Le curseur a tenté de revenir en arrière, mais l'interface utilisateur de fusion était une mer de vert et de rouge et je n'étais pas à l'aise avec le changement. Nouvelle stratégie : mettons en place quelques tests Playwright simples, puis travaillons à leur amélioration progressive. Peut-être que ce sera mieux…

J'ai caché la liste de tests proposée car j'ai aimé où cela allait, puis j'ai fermé la fenêtre Cursor Composer et démarré un nouveau Composer qui, je crois, supprime tout le contenu du Composer précédent.

Essayons à nouveau avec un point de départ plus simple. De toute façon, le développement itératif est généralement préférable.

[INVITE]

Je voudrais ajouter des tests de navigateur de bout en bout à ce projet en utilisant Playwright et Python. Veuillez me faire savoir quelles bibliothèques installer, créer des tests pour les 10 principaux scénarios en examinant les principales fonctionnalités du produit et dites-moi comment exécuter ces tests à partir de Cursor.

[/PROMPT]

Nous avons eu des problèmes similaires cette fois avec Claude voulant tester une fonctionnalité qui n'existe pas encore. Il est temps de gronder Claude !

[INVITE]

Je vois que vous créez des tests pour la fonctionnalité d'authentification. Bien que nous ayons une page de connexion, celle-ci n’est qu’un espace réservé et ne fonctionne pas réellement. Il n'a même pas de champs pour permettre à quiconque de se connecter. Veuillez revoir le code du projet et proposer les 10 meilleurs scénarios de test pour Playwright.

[/PROMPT]

Cela a amené Claude à s'excuser et à créer un tas de scénarios de test tout autour de la fonctionnalité de recherche sur la page d'accueil. J'espérais ne pas alimenter manuellement les tests que je voulais, mais je voulais plutôt qu'il trouve les fonctionnalités en regardant le code. Pas de chance, alors je suis revenu avec :

[INVITE]

Cela semble mieux mais est trop axé sur la recherche. Nous avons besoin de tests pour les fonctionnalités suivantes : rechercher, créer un sujet, modifier un sujet, supprimer des sujets, créer un article, modifier un article, supprimer un article, afficher un article et quelques tests réactifs pour nous assurer que tout semble OK sur différentes résolutions d'écran.

[/PROMPT]

Nous commençons déjà à prendre une spirale… Cela a créé le cadre de base pour quelques tests supplémentaires, mais cela fait trop d'hypothèses sur les données qui existeront. Ne faites aucune hypothèse. C'est pourquoi il est préférable d'avoir une base de données de test pré-amorcée, mais nous essaierons d'y arriver éventuellement. Pour l'instant…

[INVITE]

Certains de ces tests supposent que certains liens seront valides et que certains contenus existeront. Cela peut ne pas être le cas si des articles ou des sujets sont supprimés. Veuillez rendre chaque test autonome en créant les données dont il a besoin, puis en les supprimant une fois le test terminé.

[/PROMPT]

Alors maintenant, Claude est de retour à la création de luminaires de toute façon ! Je suppose qu’il n’y a aucun moyen de contourner ce problème si vous voulez le faire correctement…

Un autre problème concerne l'utilisation de chaînes de test telles que « Sujet de test » et « Article de test » qui peuvent entrer en conflit si nous exécutons des tests en parallèle, ce qui est une approche courante pour accélérer l'exécution. Je voulais que les tests utilisent des données randomisées, j'ai donc demandé ceci :

[INVITE]

Veuillez utiliser des données aléatoires pour le nom du sujet, le nom de l'article et le contenu de l'article. Ce serait également une bonne idée d'ajouter un test pour les caractères de langue étrangère pour s'assurer qu'ils apparaissent correctement lors de la navigation et de la recherche.

[/PROMPT]

Part  Using Cursor and Claude to Create Automated Tests with Playwright

J'ai le sentiment que nous allons avoir besoin de beaucoup plus d'ajustements, mais cela semble être un début très raisonnable. Claude a renvoyé ce qui suit :

Ces modifications ont été apportées :
Utilisez Faker pour générer des données aléatoires dans plusieurs langues
Ajouter des tests spécifiques pour les contenus multilingues
Vérifier le bon affichage des différents jeux de caractères
Testez la fonctionnalité de recherche avec des caractères non latins
Vérifiez qu'il n'y a aucun problème d'encodage de caractères dans l'affichage
Testez la création de contenu en plusieurs langues
Les tests vérifient désormais que votre application gère correctement :
Japonais (日本語)
Chinois (中文)
Coréen (한국어)
Russe (Русский)
Et du contenu régulier en anglais
Chaque test crée ses propres données aléatoires et nettoie après lui-même, rendant les tests plus fiables et indépendants.

Voici les tests qui ont été créés :

Part  Using Cursor and Claude to Create Automated Tests with Playwright

Part  Using Cursor and Claude to Create Automated Tests with Playwright

Maintenant, exécutez-les. Tout d’abord, je dois installer la bibliothèque faker que Claude m’a demandé de faire…

On m'a donné un tas de drapeaux et d'options différents pour exécuter les tests. D'après mon expérience précédente, toutes ces instructions semblent correctes, mais je vais utiliser le fichier pytest.ini créé par Claude et transmettre quelques indicateurs pour une sortie détaillée, des captures d'écran et une exécution de test ralentie afin que je puisse suivre visuellement…

Part  Using Cursor and Claude to Create Automated Tests with Playwright

Et maintenant, exécutons pytest tests/e2e/ pour exécuter réellement les tests !

Tous les tests ont échoué avec cette même erreur :

Exception during DB migration:
 raise ValueError("Constraint must have a name")
ValueError: Constraint must have a name
Copier après la connexion
Copier après la connexion

Dans pytest.ini, la base_url est définie sur http://localhost:5000, ce qui me semble correct.

Je n’arrivais pas à comprendre pourquoi ça échouait alors j’ai demandé à Claude. Il a fait quelques petits ajustements puis m'a suggéré de déplacer le fichier pytest.ini vers le répertoire ROOT du projet et hors du répertoire tests/e2e où il l'avait initialement placé. J'ai repoussé cela et il a dit que c'était bien là où il se trouvait. OK alors…

Il m'a également suggéré d'utiliser des URL absolues dans les tests au lieu de l'URL définie dans le fichier INI et les éléments de texte. Faux. J'ai également repoussé ce point et il a accepté et l'a corrigé. Perdre la foi ici…

Avec ces changements, j'ai refait les tests et maintenant je vois le navigateur s'ouvrir et accéder à l'URL de base qui est la page d'accueil de la base de connaissances mais tous les tests échouent toujours. J'ai fait quelques tours supplémentaires avec Claude et il semble que les problèmes de page racine soient résolus, mais maintenant nous échouons avec :

playwright._impl._errors.Error: Protocol error (Page.navigate): Cannot navigate to invalid URL
Copier après la connexion

Ce qui ressemble davantage à un problème de localisation.

[INVITE]

Maintenant, tous les tests d'administration dans test_admin.py échouent avec cette erreur : admin_page.fill("#topic-title", data["title"]). Ce n'est pas le bon localisateur. Veuillez corriger.

[/PROMPT]

Claude a corrigé un test mais les autres échouent toujours à cause d'erreurs de localisation. Je suis devenu plus explicite :

[INVITE]

À part test_create_topic, le reste des tests dans @test_admin.py échouent avec des erreurs de localisateur. Veuillez examiner tous les localisateurs dans les tests et les corriger.

[/PROMPT]

Claude a fait quelques modifications et maintenant nous avons un autre problème de localisateur…

[INVITE]

Maintenant, tous les tests échouent avec :
tests/e2e/test_admin.py::test_create_topic[chromium] - AssertionError : le localisateur devrait être visible

[/PROMPT]

Il est évident que nous serons là pendant un moment, à tourner en rond pendant que Claude fait les réparations nécessaires. Ce qui est également évident et regrettable, c'est que Claude n'a pas le bon contexte des éléments de l'application et de la page sans que je doive être très explicite. Il ne suffit pas de demander à Claude de « regarder le code et de créer des tests ». Vous devrez être très familier avec les fonctionnalités des fonctionnalités et la structure des pages afin de pouvoir les suivre.

Claude a été utile dans la mise en place de l'architecture des tests avec pytest.ini et conftest.py mais malgré cela, il a fallu plusieurs ajustements pour qu'un test de base s'exécute sans intervention immédiate. échec.

Ce projet utilise Bootstrap sur le front-end ainsi que la confirmation Javascript et les boîtes de dialogue modales. Claude semble avoir beaucoup de mal avec ceux-ci s'il y a plusieurs modaux dans le code source, où un seul est visible, ce qui est un modèle de conception courant. Après plusieurs itérations et en le guidant avec du pseudo-code, nous sommes finalement parvenus à une compréhension et à un test de réussite.

Tout au long de ces tests, Claude a fait de nombreuses hypothèses sur les noms des localisateurs, dont la plupart n'existaient nulle part dans le code source. Ce n'est qu'après lui avoir explicitement demandé de rechercher dans certains fichiers qu'il a pu nettoyer, mais pourquoi faire des hypothèses ? Peut-être que je ne lui ai pas fourni les bons fichiers au départ ? Je ne sais toujours pas comment tout cela est censé fonctionner.

Parfois, il semble avoir accès à l'intégralité du projet tandis que d'autres fois, j'ai besoin d'être beaucoup plus explicite. S'il a besoin d'accéder à un fichier, il doit le demander et ne pas simplement créer du code absurde. N'oubliez pas que chaque aller-retour vous coûte des crédits API.

En plus de nombreux échecs de tests, j'ai également des problèmes avec les captures d'écran qui ne sont pas enregistrées même si je passe le drapeau dans le fichier pytest.ini. Claude m'a proposé quelques permutations mais aucune n'a résolu le problème. J'ai regardé la documentation de Playwright et toujours pas de résolution. Cela semble être un autre de ces problèmes qui « devraient être faciles à résoudre », mais vous pouvez facilement graver une douzaine de requêtes Claude et n'aboutir à rien rapidement. Je vais continuer pour l'instant, en utilisant une solution de contournement suggérée par Claude.

Après avoir passé BEAUCOUP TROP de temps à faire des ajustements avec Claude, je n'ai maintenant que deux tests qui réussissent et un troisième qui commence comme PASS mais finit par être FAIL en raison d'un conflit entre le code du test et le code de l'appareil. Cela devient épuisant de déboguer et j'ai l'impression d'avoir des conversations circulaires. J'en suis arrivé à un point où je fusionne aveuglément les modifications de code suggérées et espère un miracle.

Plus tôt dans ce chapitre, mon intention était de créer un harnais de test qui ensemençait et supprimait les données de test ainsi que des appareils et des fonctions réutilisables pour garder les données et le code de test propres. Ces intentions ont été abandonnées depuis longtemps et maintenant je veux juste que les tests réussissent et j'essaierai de les nettoyer plus tard. Faites-moi savoir si quelque chose de tout cela vous semble familier…

Même quelque chose qui semble aussi simple que d'agrandir la fenêtre du navigateur au lancement s'avère bien trop difficile. Claude a fait des tentatives avec Python et Javascript et ça ne marche pas. Il ne sait pas pourquoi et les génies de Stack Overflow ont répondu à cette question à plusieurs reprises et leurs suggestions ne fonctionnent pas non plus. Je suppose qu'il y a un conflit de code entre les fichiers, mais je ne connais pas suffisamment le code pour le comprendre pour le moment. Où est l'IA quand vous en avez besoin !?

J'ai découvert que certains codes de test générés contenaient plus d'une attente/assertion. Je pense que c'est une bonne pratique de n'avoir qu'UNE SEULE assertion par test, mais sachez que ce n'est pas toujours un cas réaliste, surtout lorsque les tests sont nouveaux et que vous ne leur faites pas encore confiance.

Je me suis retrouvé à être un « ingénieur rapide » essayant de comprendre comment pousser les choses dans la bonne direction. Comme je n'ai écrit aucun code produit moi-même, je n'étais pas familier avec son fonctionnement interne et j'espérais que Claude pourrait le récupérer et l'utiliser. Après tout, c’est lui qui l’a écrit mais il semble avoir la mémoire courte. Il vous en donne assez pour démarrer, mais certainement pas assez pour demander une fois et récupérer l'argent.

Ce qui faciliterait la vie, c'est d'avoir des API pour appeler des fonctions CRUD qui créent et suppriment des données, laissant les tests de bout en bout tester uniquement leurs fonctionnalités prévues. Les lacunes et les fonctionnalités manquantes de ce projet de test peuvent vous sembler trop familières si vous avez déjà écrit des tests automatisés pour une application logicielle. Vous finissez souvent par devoir contourner les lacunes du produit avant de réellement tester les fonctionnalités du produit. Vous vous souviendrez peut-être, dans le premier chapitre, que j'avais l'intention de créer le produit en priorité API et que cela est rapidement devenu incontrôlable. En l'absence d'API, des appels SQL directs auraient peut-être été plus judicieux pour l'installation et le démontage.

Si vous avez des tests automatisés travaillant dans un autre projet et que vous êtes familier avec le code et la structure des pages d'un nouveau projet, le copier/coller/ajuster vous mènera probablement plus loin que l'approche de Claude Playwright décrite ici. Au moins, vous aurez une certaine familiarité avec le code et pourrez le modifier en toute confiance. Pour l’instant (novembre 2024), je trouve que demander à Claude de générer des tests de bout en bout avec Playwright est un exercice pénible.

Part  Using Cursor and Claude to Create Automated Tests with Playwright


À PROPOS DE L'AUTEUR

Joe Giglio est un vétéran de 25 ans dans l'industrie du logiciel. Au cours de sa carrière, il a travaillé pour un FAI local, des startups de toutes tailles et une entreprise bien établie et à évolution lente. Des leçons importantes ont été apprises à chaque arrêt.

Ses projets récents incluent :

Formation et conseil en travail à distance : chiefremoteofficer.com

Livre Kindle « Faire du travail à distance, travaillez pour vous »

Classements d'entreprises à distance. Pensez « Glassdoor pour les entreprises distantes » : remotescorecard.com

Les principes directeurs de Joe sont : le télétravail d'abord, la qualité, le champion du client et l'apprentissage tout au long de la vie. Il était introverti et pratiquait la distanciation sociale bien avant que ce soit cool !

Il réside actuellement en Caroline du Nord et est toujours intéressé par de nouvelles opportunités, rencontrer des personnes de qualité et découvrir des projets passionnants.

Contactez Joe Giglio : joe -AT- joegiglio.org | Twitter | LinkedIn

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!