Tester son intégration
Il n’existe ni bac à sable ni mode test. Une réservation prise par le widget est une vraie réservation dans l’agenda d’un vrai restaurant, et le restaurant en est notifié comme de n’importe quelle autre.
Testez contre un restaurant que vous contrôlez, ou avec un restaurant prévenu. L’écran de confirmation porte un lien Modifier ou annuler : utilisez-le sur chaque réservation que vous créez, avant que le restaurant n’ait à le faire.
Les défaillances qui ne disent rien
Section intitulée « Les défaillances qui ne disent rien »La plupart des erreurs d’intégration se manifestent par un widget qui fonctionne parfaitement et qui, discrètement, en fait moins que prévu. Voici la liste à parcourir avant la mise en production.
| Ce que vous voyez | Ce que cela signifie |
|---|---|
| Aucun bouton de retour à la fin | L’origine de return_url n’est pas dans votre liste d’autorisation. |
| Champs non préremplis, aucun message | Le jeton a été rejeté. |
| « Session expirée » | Le jeton a été vérifié, et son exp était dépassé. |
| Un champ que le client peut encore modifier | Il figure dans reservation mais pas dans locked. |
?t= ne fait rien sur votre propre page | C’est le comportement attendu — voir plus bas. |
Enregistrer les origines de retour est une étape à part
Section intitulée « Enregistrer les origines de retour est une étape à part »return_url est filtrée côté serveur contre une liste d’autorisation propre à
l’intégration. Une intégration qui livre le code sans enregistrer ses origines
n’affiche aucun bouton et ne journalise aucune erreur — le client arrive
simplement au bout de la réservation sans nulle part où revenir.
Enregistrez les origines, puis testez l’écran de confirmation, pas le chemin de code.
Distinguer un jeton rejeté d’un jeton mal formé
Section intitulée « Distinguer un jeton rejeté d’un jeton mal formé »Un jeton rejeté produit le parcours anonyme ordinaire et aucun message. C’est délibéré : une signature invalide, un émetteur inconnu, un émetteur appartenant à un autre compte, un segment malformé et une durée de vie supérieure à 15 minutes aboutissent tous au même résultat, afin qu’une vérification échouée ne révèle rien sur le contrôle qui a échoué.
Ce qui est précisément le problème lorsque la partie fautive, c’est vous. Servez-vous du seul résultat qui, lui, se distingue :
Générez un jeton correctement signé dont le exp est déjà passé. Si le
widget annonce que la session a expiré, votre signature, votre émetteur et le
restaurant sont corrects, et ce qui cloche dans votre vrai jeton se trouve dans
ses revendications ou dans sa durée de vie. S’il n’affiche rien du tout, la
défaillance est en amont : signature, émetteur, ou le compte auquel appartient le
restaurant.
Passez ensuite le reste en revue :
exp - iatne doit pas dépasser 15 minutes. Un jeton d’une durée de vie de 24 heures est rejeté d’emblée, et non raccourci — et il est rejeté comme invalide, ce qui ressemble exactement à une signature erronée.- Le MAC couvre le segment base64url tel que transmis, et non les octets JSON. Si vous re-sérialisez la charge utile avant de la hacher, l’ordre des clés ou l’échappement unicode finiront par diverger.
- Le jeton entier doit rester sous 32 768 octets une fois encodé. Mesurez la
chaîne finale, pas l’objet : le base64 ajoute un tiers, et
ensure_asciidans lejson.dumpsde Python ou lejson_encodede PHP peut tripler le texte non ASCII avant cela. - Les champs verrouillés s’écrivent avec l’orthographe snake_case du fil —
party_size,section_key,shift_id. ?t=dans la barre d’adresse de votre propre page est ignoré, à dessein. Seule la page de réservation autonome le lit ; sur votre site, utilisezsetGuestToken(). Voir liens profonds.
Les défaillances qui se font entendre
Section intitulée « Les défaillances qui se font entendre »create() lève une exception synchrone lorsque mode: "inline" et que son
conteneur est introuvable. Un sélecteur mal orthographié se manifeste donc à
l’appel plutôt que par un formulaire qui n’apparaît jamais : regardez la console
avant de conclure que le widget est cassé.
Les événements
Section intitulée « Les événements »Abonnez-vous aux deux événements de réservation et affichez-les une fois avant d’y brancher quoi que ce soit :
widget.on("reservation:created", (e) => console.log("created", e.reservation));widget.on("reservation:confirmed", (e) => console.log("confirmed", e.reservation));Dans un restaurant qui valide les réservations à la main, ou qui prend une empreinte bancaire, seul le premier est émis à la fin du parcours. C’est ce comportement qu’il faut tester, car c’est celui qui envoie un « votre table est confirmée » à un client qui n’a ni l’un ni l’autre.
step:changed rapporte les transitions et jamais l’étape sur laquelle le
parcours s’ouvre. Si la première étape de votre tunnel est vide, c’est la cause :
prenez l’entrée sur opened ou ready, voir événements.
Content-Security-Policy
Section intitulée « Content-Security-Policy »Le widget s’exécute sous la politique de votre page, pas sous la nôtre. Une page à CSP stricte a besoin de :
| Directive | Valeur | Pour |
|---|---|---|
script-src | https://app.useservice.app | Le bundle du widget. |
connect-src | https://app.useservice.app | Les appels de disponibilité et de réservation. |
img-src | L’origine qui sert le logo du restaurant, s’il y en a un. | L’en-tête. |
script-src | https://js.stripe.com | Empreintes bancaires uniquement. |
frame-src | https://js.stripe.com https://hooks.stripe.com | Empreintes bancaires et 3-D Secure. |
Le widget rappelle l’origine qui a servi son bundle : c’est pourquoi
connect-src désigne le même domaine que script-src.
Aucune entrée style-src n’est nécessaire : la feuille de style du widget est
adoptée via le CSSOM plutôt qu’injectée, et la CSP ne gouverne pas cela. Une
réserve toutefois — une politique qui définit style-src sans
style-src-attr 'unsafe-inline' bloque l’attribut en ligne qui porte la couleur
de marque du restaurant, et le widget s’affiche alors dans sa couleur par défaut.
Voir apparence.
Testez avec la politique appliquée, et non en report-only : une sous-ressource bloquée, c’est un widget qui n’apparaît pas, et la seule trace est dans la console.
Avant la mise en production
Section intitulée « Avant la mise en production »- Les réservations créées pendant les tests sont annulées.
- Les origines de retour sont enregistrées, et le bouton vérifié sur l’écran de confirmation.
- Les jetons sont générés sur votre serveur, à chaque ouverture du widget, jamais dans le source de la page.
- Le client peut toujours mener la réservation à son terme avec un jeton rejeté — c’est le chemin que prend chaque session expirée.
- Les champs verrouillés correspondent à ce que votre bon contraint réellement. Un parcours dont la date, le service et le nombre de couverts sont tous épinglés, un jour où rien n’est disponible, est une impasse.
- Vos messages de confirmation sont branchés sur
reservation:confirmed, ou sur un webhook si l’enregistrement compte.