templates/test_suite/test_suite.html.twig line 1

Open in your IDE?
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>{{ site_name }}</title>
  6.     <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text></svg>">
  7.     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css"
  8.           integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous">
  9.     <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
  10.             integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
  11.             crossorigin="anonymous"></script>
  12.     <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"
  13.             integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF"
  14.             crossorigin="anonymous"></script>
  15.     <script>
  16.         window.axeptioSettings = {
  17.             clientId: "66137db6ae83de5e566cfc53",
  18.             cookiesVersion: "first-id sandbox-fr-EU",
  19.         };
  20.         (function (d, s) {
  21.             var t = d.getElementsByTagName(s)[0],
  22.                 e = d.createElement(s);
  23.             e.async = false;
  24.             e.src = "//static.axept.io/tcf/sdk.js";
  25.             e.type = "module";
  26.             t.parentNode.insertBefore(e, t);
  27.         })(document, "script");
  28.     </script>
  29.     <style>
  30.         .test-card {
  31.             border: 2px solid #dee2e6;
  32.             border-radius: 8px;
  33.             padding: 20px;
  34.             margin-bottom: 20px;
  35.             transition: background-color 0.3s ease;
  36.         }
  37.         .test-card.success { background-color: #d4edda; border-color: #28a745; }
  38.         .test-card.error { background-color: #f8d7da; border-color: #dc3545; }
  39.         .test-card.running { background-color: #fff3cd; border-color: #ffc107; }
  40.         .test-card.disabled { opacity: 0.5; pointer-events: none; }
  41.         .log-output {
  42.             background-color: #f8f9fa;
  43.             border: 1px solid #dee2e6;
  44.             border-radius: 4px;
  45.             padding: 10px;
  46.             max-height: 300px;
  47.             overflow-y: auto;
  48.             font-family: monospace;
  49.             font-size: 12px;
  50.             white-space: pre-wrap;
  51.             word-break: break-all;
  52.         }
  53.         .log-entry { margin-bottom: 5px; }
  54.         .log-entry.error { color: #dc3545; font-weight: bold; }
  55.         .log-entry.debug { color: #007bff; }
  56.         .log-entry.info { color: #28a745; }
  57.         iframe { width: 100%; height: 400px; border: 1px solid #dee2e6; border-radius: 4px; }
  58.         #globalSummary { display: none; }
  59.         #globalSummary.visible { display: block; }
  60.     </style>
  61. </head>
  62. <body>
  63. <nav class="navbar navbar-expand-lg navbar-light bg-light">
  64.     <a class="navbar-brand" href="{{ path('app_index') }}">{{ site_name }}</a>
  65. </nav>
  66. <div class="container mt-4">
  67.     <div class="row mb-3">
  68.         <div class="col-md-12">
  69.             <label for="environmentSelect" class="font-weight-bold">Environnement API</label>
  70.             <select id="environmentSelect" class="form-control form-control-lg" style="max-width: 400px;">
  71.                 <option value="preprod" selected>Preprod — api.preprod.first-id.fr</option>
  72.                 <option value="prod">Prod — api.first-id.fr</option>
  73.             </select>
  74.         </div>
  75.     </div>
  76.     <div class="row">
  77.         <div class="col-md-12">
  78.             <h1>Suite de Tests Complète</h1>
  79.             <p class="lead">Validation automatique de toutes les APIs FirstID</p>
  80.             <button id="startAllTests" class="btn btn-primary btn-lg mb-4">Démarrer tous les tests</button>
  81.         </div>
  82.     </div>
  83.     <div id="globalSummary" class="alert mb-4">
  84.         <h4 id="summaryTitle"></h4>
  85.         <p id="summaryDetails"></p>
  86.         <p id="summaryDuration"></p>
  87.     </div>
  88.     <div class="row">
  89.         <div class="col-md-12">
  90.             <div id="test1" class="test-card">
  91.                 <h3>Test 1: Premier chargement du SDK</h3>
  92.                 <p>Suppression des cookies et chargement initial du SDK</p>
  93.                 <div class="test-status"><span class="badge badge-secondary" id="test1-status">En attente</span></div>
  94.                 <div class="mt-3"><button class="btn btn-sm btn-primary" onclick="runTest1()">Exécuter Test 1</button></div>
  95.                 <div class="log-output mt-3" id="test1-log"></div>
  96.             </div>
  97.             <div id="test2" class="test-card">
  98.                 <h3>Test 2: Rechargement du SDK</h3>
  99.                 <p>Rechargement du SDK sans suppression des cookies</p>
  100.                 <div class="test-status"><span class="badge badge-secondary" id="test2-status">En attente</span></div>
  101.                 <div class="mt-3">
  102.                     <button class="btn btn-sm btn-primary" onclick="runTest2()">Exécuter Test 2</button>
  103.                     <span class="badge badge-warning ml-2">Nécessite un first id (ou Test 1)</span>
  104.                 </div>
  105.                 <div class="log-output mt-3" id="test2-log"></div>
  106.             </div>
  107.             <div id="test3" class="test-card">
  108.                 <h3>Test 3: Appels APP API</h3>
  109.                 <p>Tests des appels APP API</p>
  110.                 <div class="test-status"><span class="badge badge-secondary" id="test3-status">En attente</span></div>
  111.                 <div class="mt-3"><button class="btn btn-sm btn-primary" onclick="runTest3()">Exécuter Test 3</button></div>
  112.                 <div class="log-output mt-3" id="test3-log"></div>
  113.             </div>
  114.             <div id="test4" class="test-card">
  115.                 <h3>Test 4: Redirection Gate</h3>
  116.                 <p>Test de la redirection vers la gate dans une iframe (page dédiée)</p>
  117.                 <div class="test-status"><span class="badge badge-secondary" id="test4-status">En attente</span></div>
  118.                 <div class="mt-3"><button class="btn btn-sm btn-primary" onclick="runTest4()">Exécuter Test 4</button></div>
  119.                 <div class="log-output mt-3" id="test4-log"></div>
  120.                 <div class="mt-3" id="test4-iframe-container"></div>
  121.             </div>
  122.             <div id="test5" class="test-card">
  123.                 <h3>Test 5: SDK Premium Lite dans iframe</h3>
  124.                 <p>Test du SDK Premium Lite chargé dans une iframe dédiée</p>
  125.                 <div class="test-status"><span class="badge badge-secondary" id="test5-status">En attente</span></div>
  126.                 <div class="mt-3"><button class="btn btn-sm btn-primary" onclick="runTest5()">Exécuter Test 5</button></div>
  127.                 <div class="log-output mt-3" id="test5-log"></div>
  128.                 <div class="mt-3" id="test5-iframe-container"></div>
  129.             </div>
  130.             <div id="test6" class="test-card">
  131.                 <h3>Test 6: Email hashé</h3>
  132.                 <p>Test de l'ajout d'un email hashé via le SDK</p>
  133.                 <div class="test-status"><span class="badge badge-secondary" id="test6-status">En attente</span></div>
  134.                 <div class="mt-3">
  135.                     <button class="btn btn-sm btn-primary" onclick="runTest6()">Exécuter Test 6</button>
  136.                     <span class="badge badge-warning ml-2">Nécessite un SDK chargé (ou Test 1)</span>
  137.                 </div>
  138.                 <div class="log-output mt-3" id="test6-log"></div>
  139.             </div>
  140.             <div id="test7" class="test-card">
  141.                 <h3>Test 7: setCustomData avec cxenseid</h3>
  142.                 <p>Test de l'ajout de customData (cxenseid) et récupération du firstId après suppression des cookies</p>
  143.                 <div class="test-status"><span class="badge badge-secondary" id="test7-status">En attente</span></div>
  144.                 <div class="mt-3">
  145.                     <button class="btn btn-sm btn-primary" onclick="runTest7()">Exécuter Test 7</button>
  146.                     <span class="badge badge-warning ml-2">Nécessite un SDK chargé (ou Test 1)</span>
  147.                 </div>
  148.                 <div class="log-output mt-3" id="test7-log"></div>
  149.             </div>
  150.             <div id="test8" class="test-card">
  151.                 <h3>Test 8: getDeviceId et getFirstIdEidsObject</h3>
  152.                 <p>Test de récupération du deviceId et de l'objet eids pour Prebid.js</p>
  153.                 <div class="test-status"><span class="badge badge-secondary" id="test8-status">En attente</span></div>
  154.                 <div class="mt-3">
  155.                     <button class="btn btn-sm btn-primary" onclick="runTest8()">Exécuter Test 8</button>
  156.                     <span class="badge badge-warning ml-2">Nécessite un SDK chargé (ou Test 1)</span>
  157.                 </div>
  158.                 <div class="log-output mt-3" id="test8-log"></div>
  159.             </div>
  160.             <div id="test9" class="test-card">
  161.                 <h3>Test 9: getMasterFirstId</h3>
  162.                 <p>Test de récupération du master firstId depuis un slave firstId</p>
  163.                 <div class="test-status"><span class="badge badge-secondary" id="test9-status">En attente</span></div>
  164.                 <div class="mt-3">
  165.                     <button class="btn btn-sm btn-primary" onclick="runTest9()">Exécuter Test 9</button>
  166.                     <span class="badge badge-info ml-2">Prépare automatiquement les données</span>
  167.                 </div>
  168.                 <div class="log-output mt-3" id="test9-log"></div>
  169.             </div>
  170.         </div>
  171.     </div>
  172. </div>
  173. <script>
  174.     const COOKIES_TO_DELETE = [
  175.         'firstid', 'firstid_flex_type', 'fid_email_hashed', 'fid_email_hash',
  176.         'fidsdk_consent', 'fid_customdata_hash', 'fidflexlastsync',
  177.         'fidflexemaillastsync', 'firstid_refresh', 'fidflexlastcheck'
  178.     ];
  179.     const SDK_LOAD_TIMEOUT_MS = 5000;
  180.     const IFRAME_TIMEOUT_MS = 20000;
  181.     const FIRSTID_VENDOR_ID = 1178;
  182.     const MAID_MATCHING_API_PROXY_URL = '/test-suite/api-proxy';
  183.     const TOTAL_TESTS = 9;
  184.     const API_PREPROD_BASE = 'https://api.preprod.first-id.fr';
  185.     const API_PROD_BASE = 'https://api.first-id.fr';
  186.     const CDN_PREPROD_BASE = 'https://cdn.preprod.first-id.fr';
  187.     const CDN_PROD_BASE = 'https://cdn.first-id.fr';
  188.     const DELETE_FG_PREPROD_V4 = 'https://api-v4.preprod.first-id.fr/fg';
  189.     const DELETE_FG_PREPROD_V6 = 'https://api-v6.preprod.first-id.fr/fg';
  190.     let testState = {};
  191.     let originalConsoleDebug = console.debug;
  192.     let originalConsoleError = console.error;
  193.     let consoleInterceptActive = false;
  194.     let interceptedErrors = [];
  195.     function resetTestState() {
  196.         testState = {
  197.             results: {},
  198.             hasConsent: false,
  199.             suiteStartTime: null
  200.         };
  201.     }
  202.     resetTestState();
  203.     function getSelectedEnvironment() {
  204.         const select = document.getElementById('environmentSelect');
  205.         return select && select.value === 'prod' ? 'prod' : 'preprod';
  206.     }
  207.     function getApiBaseUrl() {
  208.         return getSelectedEnvironment() === 'prod' ? API_PROD_BASE : API_PREPROD_BASE;
  209.     }
  210.     function getCdnBaseUrl() {
  211.         return getSelectedEnvironment() === 'prod' ? CDN_PROD_BASE : CDN_PREPROD_BASE;
  212.     }
  213.     function getCdnLoaderFlexUrl() {
  214.         return getCdnBaseUrl() + '/sdk/loader/loader-latest-flex.js?id=1234567890';
  215.     }
  216.     function getCdnLoaderPremiumLiteUrl() {
  217.         return getCdnBaseUrl() + '/sdk/loader/loader-latest-premium-lite.js?id=1234567890';
  218.     }
  219.     function setupConsoleInterceptor(testNumber) {
  220.         interceptedErrors = [];
  221.         consoleInterceptActive = true;
  222.         console.debug = function (...args) {
  223.             if (consoleInterceptActive) {
  224.                 logToTest(testNumber, 'debug', '[DEBUG] ' + args.join(' '));
  225.             }
  226.             originalConsoleDebug.apply(console, args);
  227.         };
  228.         console.error = function (...args) {
  229.             if (consoleInterceptActive) {
  230.                 interceptedErrors.push(args.join(' '));
  231.                 logToTest(testNumber, 'error', '[ERROR] ' + args.join(' '));
  232.             }
  233.             originalConsoleError.apply(console, args);
  234.         };
  235.     }
  236.     function teardownConsoleInterceptor() {
  237.         consoleInterceptActive = false;
  238.         console.debug = originalConsoleDebug;
  239.         console.error = originalConsoleError;
  240.     }
  241.     function logToTest(testNumber, level, message) {
  242.         const logElement = document.getElementById(`test${testNumber}-log`);
  243.         if (!logElement) return;
  244.         const entry = document.createElement('div');
  245.         entry.className = `log-entry ${level}`;
  246.         entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
  247.         logElement.appendChild(entry);
  248.         logElement.scrollTop = logElement.scrollHeight;
  249.     }
  250.     function setTestStatus(testNumber, status, message) {
  251.         const statusElement = document.getElementById(`test${testNumber}-status`);
  252.         const testCard = document.getElementById(`test${testNumber}`);
  253.         testCard.classList.remove('running', 'success', 'error');
  254.         const statusMapping = {
  255.             running: { className: 'badge badge-warning', text: 'En cours...' },
  256.             success: { className: 'badge badge-success', text: 'Réussi' },
  257.             error:   { className: 'badge badge-danger',  text: 'Échec' },
  258.             waiting: { className: 'badge badge-secondary', text: 'En attente' }
  259.         };
  260.         const statusConfig = statusMapping[status];
  261.         if (statusConfig) {
  262.             statusElement.className = statusConfig.className;
  263.             statusElement.textContent = statusConfig.text;
  264.             if (status !== 'waiting') testCard.classList.add(status);
  265.         }
  266.         if (message) {
  267.             logToTest(testNumber, status === 'error' ? 'error' : 'info', message);
  268.         }
  269.     }
  270.     function resetAllTestStatuses() {
  271.         for (let testIndex = 1; testIndex <= TOTAL_TESTS; testIndex++) {
  272.             setTestStatus(testIndex, 'waiting');
  273.             const logElement = document.getElementById(`test${testIndex}-log`);
  274.             if (logElement) logElement.innerHTML = '';
  275.         }
  276.         const summaryElement = document.getElementById('globalSummary');
  277.         summaryElement.classList.remove('visible', 'alert-success', 'alert-danger', 'alert-warning');
  278.     }
  279.     function deleteCookies() {
  280.         const domain = window.location.hostname.split('.').slice(-2).join('.');
  281.         COOKIES_TO_DELETE.forEach(cookieName => {
  282.             document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${domain}`;
  283.             document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.${domain}`;
  284.             document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;
  285.         });
  286.     }
  287.     function getCookieValue(cookieName) {
  288.         const cookieArray = document.cookie.split(";");
  289.         for (let index = 0; index < cookieArray.length; index++) {
  290.             const cookiePair = cookieArray[index].split("=");
  291.             if (cookieName === cookiePair[0].trim()) {
  292.                 return decodeURIComponent(cookiePair[1]);
  293.             }
  294.         }
  295.         return null;
  296.     }
  297.     async function deleteFingerprints(testNumber) {
  298.         if (getSelectedEnvironment() === 'prod') {
  299.             logToTest(testNumber, 'info', 'Environnement prod: suppression des fingerprints non disponible, étape ignorée');
  300.             return;
  301.         }
  302.         logToTest(testNumber, 'info', 'Suppression des fingerprints dans la matrice...');
  303.         const browserSignature = [
  304.             navigator?.userAgent ?? '',
  305.             navigator?.language ?? '',
  306.             screen?.width ?? 0,
  307.             screen?.height ?? 0,
  308.             navigator?.deviceMemory ?? 0,
  309.             navigator?.hardwareConcurrency ?? 0
  310.         ].join("::");
  311.         const queryParams = new URLSearchParams({ bs: browserSignature });
  312.         const deleteUrlV4 = DELETE_FG_PREPROD_V4 + '?' + queryParams.toString();
  313.         const deleteUrlV6 = DELETE_FG_PREPROD_V6 + '?' + queryParams.toString();
  314.         const [responseV4, responseV6] = await Promise.allSettled([
  315.             fetch(deleteUrlV4, { method: 'DELETE', credentials: 'include' }),
  316.             fetch(deleteUrlV6, { method: 'DELETE', credentials: 'include' })
  317.         ]);
  318.         const isV4Ok = responseV4.status === 'fulfilled' && responseV4.value.ok;
  319.         const isV6Ok = responseV6.status === 'fulfilled' && responseV6.value.ok;
  320.         if (isV4Ok || isV6Ok) {
  321.             logToTest(testNumber, 'info', 'Fingerprints supprimés avec succès');
  322.         } else {
  323.             logToTest(testNumber, 'debug', 'Suppression des fingerprints échouée (non bloquant)');
  324.         }
  325.     }
  326.     function cleanSdkGlobals() {
  327.         delete window.FIRSTID;
  328.         delete window.FIRSTID_BY_TYPE;
  329.         delete window.FIRSTID_LOADING;
  330.         const existingScripts = document.querySelectorAll('script[src*="first-id.fr"]');
  331.         existingScripts.forEach(script => script.remove());
  332.     }
  333.     function configureSdkWindow(extraConfig = {}) {
  334.         window.firstId = {
  335.             callbacks: [],
  336.             debug: true,
  337.             cookieName: 'firstid',
  338.             firstIdFlexFeature: true,
  339.             cookieSyncEnabled: false,
  340.             ...extraConfig
  341.         };
  342.     }
  343.     function loadFirstIdScript(testNumber, scriptUrl) {
  344.         const loaderUrl = scriptUrl || getCdnLoaderFlexUrl();
  345.         return new Promise((resolve, reject) => {
  346.             if (document.querySelector('script[src*="first-id.fr"]')) {
  347.                 logToTest(testNumber, 'info', 'Script FirstID déjà chargé');
  348.                 resolve();
  349.                 return;
  350.             }
  351.             const script = document.createElement('script');
  352.             script.src = loaderUrl;
  353.             script.defer = true;
  354.             script.onload = () => {
  355.                 logToTest(testNumber, 'info', 'Script FirstID chargé avec succès');
  356.                 resolve();
  357.             };
  358.             script.onerror = () => reject(new Error('Échec du chargement du script First-ID'));
  359.             document.head.appendChild(script);
  360.         });
  361.     }
  362.     function waitForFirstIdInitialized(testNumber, timeoutMs = SDK_LOAD_TIMEOUT_MS) {
  363.         return new Promise((resolve, reject) => {
  364.             let settled = false;
  365.             const timeout = setTimeout(() => {
  366.                 if (settled) return;
  367.                 settled = true;
  368.                 document.removeEventListener('firstId:initialized', handler);
  369.                 reject(new Error(`Timeout FirstID après ${timeoutMs}ms`));
  370.             }, timeoutMs);
  371.             function handler(event) {
  372.                 if (settled) return;
  373.                 settled = true;
  374.                 clearTimeout(timeout);
  375.                 document.removeEventListener('firstId:initialized', handler);
  376.                 const firstId = event.detail?.firstId || event.detail;
  377.                 logToTest(testNumber, 'info', `FirstID initialisé: ${firstId}`);
  378.                 resolve(firstId);
  379.             }
  380.             document.addEventListener('firstId:initialized', handler);
  381.         });
  382.     }
  383.     async function ensureSdkLoaded(testNumber, extraConfig = {}) {
  384.         if (window.FIRSTID && window.FIRSTID.getId && window.FIRSTID.getId()) {
  385.             logToTest(testNumber, 'info', 'SDK déjà chargé, réutilisation');
  386.             return window.FIRSTID.getId();
  387.         }
  388.         cleanSdkGlobals();
  389.         configureSdkWindow(extraConfig);
  390.         await loadFirstIdScript(testNumber);
  391.         logToTest(testNumber, 'info', 'Attente de l\'initialisation du SDK...');
  392.         const firstId = await waitForFirstIdInitialized(testNumber);
  393.         await new Promise(resolve => setTimeout(resolve, 500));
  394.         return firstId;
  395.     }
  396.     function listenForIframeMessage(expectedType, testNumber, timeoutMs = IFRAME_TIMEOUT_MS) {
  397.         return new Promise((resolve, reject) => {
  398.             let settled = false;
  399.             const timeout = setTimeout(() => {
  400.                 if (settled) return;
  401.                 settled = true;
  402.                 window.removeEventListener('message', handler);
  403.                 reject(new Error(`Timeout iframe après ${timeoutMs / 1000} secondes`));
  404.             }, timeoutMs);
  405.             function handler(event) {
  406.                 if (!event.data || !event.data.type) return;
  407.                 if (event.data.type === 'iframeLog') {
  408.                     logToTest(testNumber, 'debug', `[IFRAME] ${event.data.message}`);
  409.                     return;
  410.                 }
  411.                 if (event.data.type === expectedType) {
  412.                     if (settled) return;
  413.                     settled = true;
  414.                     clearTimeout(timeout);
  415.                     window.removeEventListener('message', handler);
  416.                     resolve(event.data);
  417.                     return;
  418.                 }
  419.                 if (event.data.type === 'scriptError' || event.data.type === 'gateError') {
  420.                     if (settled) return;
  421.                     settled = true;
  422.                     clearTimeout(timeout);
  423.                     window.removeEventListener('message', handler);
  424.                     reject(new Error(event.data.error || 'Erreur dans l\'iframe'));
  425.                 }
  426.             }
  427.             window.addEventListener('message', handler);
  428.         });
  429.     }
  430.     function showGlobalSummary() {
  431.         const summaryElement = document.getElementById('globalSummary');
  432.         const passedTests = Object.values(testState.results).filter(result => result === true).length;
  433.         const failedTests = Object.values(testState.results).filter(result => result === false).length;
  434.         const totalExecuted = passedTests + failedTests;
  435.         const durationMs = Date.now() - testState.suiteStartTime;
  436.         const durationSeconds = (durationMs / 1000).toFixed(1);
  437.         document.getElementById('summaryTitle').textContent =
  438.             passedTests === totalExecuted ? 'Tous les tests sont passés' : `${failedTests} test(s) échoué(s)`;
  439.         document.getElementById('summaryDetails').textContent =
  440.             `${passedTests}/${totalExecuted} tests réussis`;
  441.         document.getElementById('summaryDuration').textContent =
  442.             `Durée totale: ${durationSeconds}s`;
  443.         summaryElement.classList.remove('alert-success', 'alert-danger', 'alert-warning');
  444.         if (failedTests === 0) {
  445.             summaryElement.classList.add('alert-success');
  446.         } else if (passedTests === 0) {
  447.             summaryElement.classList.add('alert-danger');
  448.         } else {
  449.             summaryElement.classList.add('alert-warning');
  450.         }
  451.         summaryElement.classList.add('visible');
  452.     }
  453.     async function runTest1() {
  454.         const testNumber = 1;
  455.         setTestStatus(testNumber, 'running', 'Démarrage du Test 1...');
  456.         setupConsoleInterceptor(testNumber);
  457.         try {
  458.             logToTest(testNumber, 'info', 'Suppression des cookies...');
  459.             deleteCookies();
  460.             logToTest(testNumber, 'info', 'Cookies supprimés');
  461.             logToTest(testNumber, 'info', 'Réinitialisation de la matrice (fingerprints)...');
  462.             await deleteFingerprints(testNumber);
  463.             logToTest(testNumber, 'info', 'Chargement du script FirstID...');
  464.             cleanSdkGlobals();
  465.             configureSdkWindow();
  466.             await loadFirstIdScript(testNumber);
  467.             logToTest(testNumber, 'info', 'Initialisation du SDK...');
  468.             const firstId = await waitForFirstIdInitialized(testNumber);
  469.             if (!firstId) throw new Error('FirstID non obtenu après initialisation');
  470.             if (interceptedErrors.length > 0) {
  471.                 throw new Error(`${interceptedErrors.length} erreur(s) console détectée(s)`);
  472.             }
  473.             logToTest(testNumber, 'info', `✓ FirstID obtenu: ${firstId}`);
  474.             logToTest(testNumber, 'info', '✓ Aucune erreur console détectée');
  475.             setTestStatus(testNumber, 'success', 'Test 1 réussi');
  476.             testState.results[testNumber] = true;
  477.         } catch (error) {
  478.             setTestStatus(testNumber, 'error', `Test 1 échoué: ${error.message}`);
  479.             testState.results[testNumber] = false;
  480.         } finally {
  481.             teardownConsoleInterceptor();
  482.         }
  483.     }
  484.     async function runTest2() {
  485.         const testNumber = 2;
  486.         setTestStatus(testNumber, 'running', 'Démarrage du Test 2...');
  487.         setupConsoleInterceptor(testNumber);
  488.         try {
  489.             logToTest(testNumber, 'info', 'Rechargement du SDK sans suppression des cookies...');
  490.             cleanSdkGlobals();
  491.             configureSdkWindow();
  492.             logToTest(testNumber, 'info', 'Variables globales réinitialisées');
  493.             await loadFirstIdScript(testNumber);
  494.             logToTest(testNumber, 'info', 'Initialisation du SDK...');
  495.             const firstId = await waitForFirstIdInitialized(testNumber);
  496.             if (!firstId) throw new Error('FirstID non obtenu après réinitialisation');
  497.             if (interceptedErrors.length > 0) {
  498.                 throw new Error(`${interceptedErrors.length} erreur(s) console détectée(s)`);
  499.             }
  500.             logToTest(testNumber, 'info', `✓ FirstID obtenu: ${firstId}`);
  501.             logToTest(testNumber, 'info', '✓ Aucune erreur console détectée');
  502.             setTestStatus(testNumber, 'success', 'Test 2 réussi');
  503.             testState.results[testNumber] = true;
  504.         } catch (error) {
  505.             setTestStatus(testNumber, 'error', `Test 2 échoué: ${error.message}`);
  506.             testState.results[testNumber] = false;
  507.         } finally {
  508.             teardownConsoleInterceptor();
  509.         }
  510.     }
  511.     async function callMaidMatchingApi(payload) {
  512.         const response = await fetch(MAID_MATCHING_API_PROXY_URL, {
  513.             method: 'POST',
  514.             headers: { 'Content-Type': 'application/json' },
  515.             body: JSON.stringify(payload)
  516.         });
  517.         if (!response.ok) {
  518.             const errorText = await response.text();
  519.             throw new Error(`API call failed: ${response.status} - ${errorText}`);
  520.         }
  521.         return await response.json();
  522.     }
  523.     function generateMobileDeviceData(variant) {
  524.         const devices = [
  525.             {
  526.                 deviceType: 'mobile_test_suite', deviceManufacturer: 'Apple',
  527.                 deviceModel: 'iPhone 14 Pro', osVersion: '17.2', buildId: '21C5050',
  528.                 deviceRam: 6000, deviceResolution: '1179x2556', appIdentifier: 'com.firstid.testapp'
  529.             },
  530.             {
  531.                 deviceType: 'mobile_test_suite', deviceManufacturer: 'Samsung',
  532.                 deviceModel: 'Galaxy S23', osVersion: '14', buildId: 'TP1A.220624.014',
  533.                 deviceRam: 8000, deviceResolution: '1080x2340', appIdentifier: 'com.firstid.testapp'
  534.             },
  535.             {
  536.                 deviceType: 'mobile_test_suite', deviceManufacturer: 'Google',
  537.                 deviceModel: 'Pixel 8', osVersion: '14', buildId: 'UP1A.231105.003',
  538.                 deviceRam: 8000, deviceResolution: '1080x2400', appIdentifier: 'com.firstid.testapp'
  539.             }
  540.         ];
  541.         const selectedDevice = devices[variant - 1] || devices[0];
  542.         return { ...selectedDevice, dfid: "true" };
  543.     }
  544.     async function runTest3() {
  545.         const testNumber = 3;
  546.         setTestStatus(testNumber, 'running', 'Démarrage du Test 3...');
  547.         try {
  548.             logToTest(testNumber, 'info', '=== Test 3: Appels APP API Mobile ===');
  549.             logToTest(testNumber, 'info', '--- Appel 1: Création initiale (sans firstId) ---');
  550.             const deviceData1 = generateMobileDeviceData(1);
  551.             const payload1 = { ...deviceData1, maid: crypto.randomUUID() };
  552.             logToTest(testNumber, 'info', `Device: ${deviceData1.deviceManufacturer} ${deviceData1.deviceModel}`);
  553.             const response1 = await callMaidMatchingApi(payload1);
  554.             if (!response1.firstId) throw new Error('Premier appel: firstId non reçu');
  555.             const obtainedFirstId = response1.firstId;
  556.             logToTest(testNumber, 'info', `✓ FirstID obtenu: ${obtainedFirstId}`);
  557.             await new Promise(resolve => setTimeout(resolve, 500));
  558.             logToTest(testNumber, 'info', '--- Appel 2: Avec firstId + données device différentes ---');
  559.             const deviceData2 = generateMobileDeviceData(2);
  560.             const payload2 = { ...deviceData2, firstId: obtainedFirstId, maid: crypto.randomUUID() };
  561.             const response2 = await callMaidMatchingApi(payload2);
  562.             if (!response2.firstId) throw new Error('Deuxième appel: firstId non reçu');
  563.             if (response2.firstId !== obtainedFirstId) {
  564.                 throw new Error('Le firstId retourné est différent de celui envoyé');
  565.             }
  566.             logToTest(testNumber, 'info', '✓ FirstID identique confirmé');
  567.             await new Promise(resolve => setTimeout(resolve, 500));
  568.             logToTest(testNumber, 'info', '--- Appel 3: Sans firstId avec mêmes données que appel 2 ---');
  569.             const payload3 = { ...deviceData2, maid: payload2.maid };
  570.             const response3 = await callMaidMatchingApi(payload3);
  571.             if (!response3.firstId) throw new Error('Troisième appel: firstId non reçu');
  572.             if (response3.firstId !== obtainedFirstId) {
  573.                 throw new Error('Le firstId retrouvé ne correspond pas au firstId initial');
  574.             }
  575.             logToTest(testNumber, 'info', '✓ FirstID retrouvé avec succès via MAID');
  576.             logToTest(testNumber, 'info', '=== Résumé: Tous les appels ont retourné le même firstId ===');
  577.             setTestStatus(testNumber, 'success', 'Test 3 réussi - API Mobile validée');
  578.             testState.results[testNumber] = true;
  579.         } catch (error) {
  580.             logToTest(testNumber, 'error', `Erreur détaillée: ${error.message}`);
  581.             setTestStatus(testNumber, 'error', `Test 3 échoué: ${error.message}`);
  582.             testState.results[testNumber] = false;
  583.         }
  584.     }
  585.     async function runTest4() {
  586.         const testNumber = 4;
  587.         setTestStatus(testNumber, 'running', 'Démarrage du Test 4...');
  588.         try {
  589.             logToTest(testNumber, 'info', 'Test de la redirection Gate via page dédiée...');
  590.             const iframeContainer = document.getElementById('test4-iframe-container');
  591.             iframeContainer.innerHTML = '';
  592.             const iframe = document.createElement('iframe');
  593.             const environment = getSelectedEnvironment();
  594.             iframe.src = `/test-suite/iframe/gate?env=${environment}`;
  595.             logToTest(testNumber, 'info', `URL iframe Gate: ${iframe.src}`);
  596.             iframeContainer.appendChild(iframe);
  597.             const messagePromise = listenForIframeMessage('gateFirstIdReceived', testNumber);
  598.             const messageData = await messagePromise;
  599.             const receivedFirstId = messageData.firstId;
  600.             logToTest(testNumber, 'info', `✓ FirstID reçu de la Gate: ${receivedFirstId}`);
  601.             await new Promise(resolve => setTimeout(resolve, 1000));
  602.             const firstIdCookie = getCookieValue('firstid');
  603.             if (firstIdCookie) {
  604.                 logToTest(testNumber, 'info', `✓ Cookie firstid trouvé: ${firstIdCookie}`);
  605.             } else {
  606.                 logToTest(testNumber, 'info', 'Cookie firstid non trouvé sur le domaine parent (attendu en cross-domain)');
  607.             }
  608.             setTestStatus(testNumber, 'success', 'Test 4 réussi');
  609.             testState.results[testNumber] = true;
  610.         } catch (error) {
  611.             setTestStatus(testNumber, 'error', `Test 4 échoué: ${error.message}`);
  612.             testState.results[testNumber] = false;
  613.         }
  614.     }
  615.     async function runTest5() {
  616.         const testNumber = 5;
  617.         setTestStatus(testNumber, 'running', 'Démarrage du Test 5...');
  618.         try {
  619.             logToTest(testNumber, 'info', '=== Test 5: SDK Premium Lite dans iframe dédiée ===');
  620.             const iframeContainer = document.getElementById('test5-iframe-container');
  621.             iframeContainer.innerHTML = '';
  622.             const iframe = document.createElement('iframe');
  623.             iframe.id = 'test5-iframe';
  624.             const environment = getSelectedEnvironment();
  625.             iframe.src = `/test-suite/iframe/premium-lite?env=${environment}`;
  626.             logToTest(testNumber, 'info', `URL iframe Premium Lite: ${iframe.src}`);
  627.             iframeContainer.appendChild(iframe);
  628.             const messageData = await listenForIframeMessage('firstIdInitialized', testNumber);
  629.             const iframeFirstId = messageData.firstId;
  630.             logToTest(testNumber, 'info', `✓ FirstID obtenu via SDK dans iframe: ${iframeFirstId}`);
  631.             await new Promise(resolve => setTimeout(resolve, 2000));
  632.             const firstIdCookie = getCookieValue('firstid');
  633.             if (firstIdCookie) {
  634.                 logToTest(testNumber, 'info', `✓ Cookie firstid vérifié: ${firstIdCookie}`);
  635.                 if (firstIdCookie === iframeFirstId) {
  636.                     logToTest(testNumber, 'info', '✓ FirstID du SDK correspond au cookie');
  637.                 } else {
  638.                     logToTest(testNumber, 'info', `FirstID SDK=${iframeFirstId}, Cookie=${firstIdCookie} (peut différer en cross-domain)`);
  639.                 }
  640.             } else {
  641.                 logToTest(testNumber, 'info', 'Cookie firstid non trouvé sur le domaine parent (attendu en cross-domain)');
  642.             }
  643.             setTestStatus(testNumber, 'success', 'Test 5 réussi');
  644.             testState.results[testNumber] = true;
  645.         } catch (error) {
  646.             setTestStatus(testNumber, 'error', `Test 5 échoué: ${error.message}`);
  647.             testState.results[testNumber] = false;
  648.         }
  649.     }
  650.     async function runTest6() {
  651.         const testNumber = 6;
  652.         setTestStatus(testNumber, 'running', 'Démarrage du Test 6...');
  653.         setupConsoleInterceptor(testNumber);
  654.         const TEST_EMAIL_HASH = 'e473c325a4d7cd827f532e93b1f61932b8acba5595c172f47c3cf498ac45d913';
  655.         try {
  656.             logToTest(testNumber, 'info', '=== Test 6: Ajout d\'un email hashé ===');
  657.             logToTest(testNumber, 'info', `Email hashé à tester: ${TEST_EMAIL_HASH}`);
  658.             await ensureSdkLoaded(testNumber);
  659.             if (!window.FIRSTID) throw new Error('SDK FirstID non disponible après chargement');
  660.             if (!window.FIRSTID.setEmailHashed) {
  661.                 throw new Error('La méthode setEmailHashed n\'est pas disponible dans ce SDK');
  662.             }
  663.             const firstIdBefore = window.FIRSTID.getId ? window.FIRSTID.getId() : null;
  664.             logToTest(testNumber, 'info', `FirstID avant ajout email: ${firstIdBefore || 'non disponible'}`);
  665.             await window.FIRSTID.setEmailHashed(TEST_EMAIL_HASH);
  666.             logToTest(testNumber, 'info', '✓ setEmailHashed appelé avec succès');
  667.             await new Promise(resolve => setTimeout(resolve, 2000));
  668.             const emailHashCookie = getCookieValue('fid_email_hashed');
  669.             if (emailHashCookie) {
  670.                 logToTest(testNumber, 'info', `✓ Cookie fid_email_hashed trouvé: ${emailHashCookie}`);
  671.             } else {
  672.                 logToTest(testNumber, 'info', 'Cookie fid_email_hashed non trouvé (peut être normal selon l\'implémentation)');
  673.             }
  674.             logToTest(testNumber, 'info', '✓ Email hashé ajouté avec succès');
  675.             setTestStatus(testNumber, 'success', 'Test 6 réussi - Email hashé ajouté');
  676.             testState.results[testNumber] = true;
  677.         } catch (error) {
  678.             logToTest(testNumber, 'error', `Erreur détaillée: ${error.message}`);
  679.             setTestStatus(testNumber, 'error', `Test 6 échoué: ${error.message}`);
  680.             testState.results[testNumber] = false;
  681.         } finally {
  682.             teardownConsoleInterceptor();
  683.         }
  684.     }
  685.     async function runTest7() {
  686.         const testNumber = 7;
  687.         setTestStatus(testNumber, 'running', 'Démarrage du Test 7...');
  688.         setupConsoleInterceptor(testNumber);
  689.         const timestamp = Date.now();
  690.         const CXENSE_ID = `TestSuite_${timestamp}`;
  691.         try {
  692.             logToTest(testNumber, 'info', '=== Test 7: setCustomData avec cxenseid ===');
  693.             logToTest(testNumber, 'info', `cxenseid à tester: ${CXENSE_ID}`);
  694.             await ensureSdkLoaded(testNumber);
  695.             if (!window.FIRSTID) throw new Error('SDK FirstID non disponible après chargement');
  696.             if (!window.FIRSTID.setCustomData) {
  697.                 throw new Error('La méthode setCustomData n\'est pas disponible dans ce SDK');
  698.             }
  699.             const firstIdInitial = window.FIRSTID.getId ? window.FIRSTID.getId() : null;
  700.             if (!firstIdInitial) throw new Error('Aucun firstId disponible avant setCustomData');
  701.             logToTest(testNumber, 'info', `FirstID initial: ${firstIdInitial}`);
  702.             await window.FIRSTID.setCustomData({ cxenseid: CXENSE_ID });
  703.             logToTest(testNumber, 'info', '✓ setCustomData appelé avec succès');
  704.             await new Promise(resolve => setTimeout(resolve, 2000));
  705.             logToTest(testNumber, 'info', 'Suppression de tous les cookies...');
  706.             deleteCookies();
  707.             logToTest(testNumber, 'info', 'Réinitialisation de la matrice (fingerprints)...');
  708.             await deleteFingerprints(testNumber);
  709.             logToTest(testNumber, 'info', 'Réinitialisation et rechargement du SDK...');
  710.             cleanSdkGlobals();
  711.             configureSdkWindow({ customData: { cxenseid: CXENSE_ID } });
  712.             await loadFirstIdScript(testNumber);
  713.             logToTest(testNumber, 'info', 'Attente de l\'initialisation du SDK...');
  714.             await waitForFirstIdInitialized(testNumber);
  715.             if (!window.FIRSTID) throw new Error('SDK FirstID non disponible après rechargement');
  716.             const firstIdRecovered = window.FIRSTID.getId ? window.FIRSTID.getId() : null;
  717.             if (!firstIdRecovered) throw new Error('Aucun firstId récupéré après rechargement avec customData');
  718.             logToTest(testNumber, 'info', `FirstID récupéré: ${firstIdRecovered}`);
  719.             if (firstIdRecovered !== firstIdInitial) {
  720.                 throw new Error('Le firstId récupéré ne correspond pas au firstId initial');
  721.             }
  722.             logToTest(testNumber, 'info', '✓ FirstID identique confirmé');
  723.             logToTest(testNumber, 'info', '✓ Le customData a permis de récupérer le même firstId');
  724.             setTestStatus(testNumber, 'success', 'Test 7 réussi - setCustomData validé');
  725.             testState.results[testNumber] = true;
  726.         } catch (error) {
  727.             logToTest(testNumber, 'error', `Erreur détaillée: ${error.message}`);
  728.             setTestStatus(testNumber, 'error', `Test 7 échoué: ${error.message}`);
  729.             testState.results[testNumber] = false;
  730.         } finally {
  731.             teardownConsoleInterceptor();
  732.         }
  733.     }
  734.     async function runTest8() {
  735.         const testNumber = 8;
  736.         setTestStatus(testNumber, 'running', 'Démarrage du Test 8...');
  737.         setupConsoleInterceptor(testNumber);
  738.         try {
  739.             logToTest(testNumber, 'info', '=== Test 8: getDeviceId et getFirstIdEidsObject ===');
  740.             await ensureSdkLoaded(testNumber);
  741.             if (!window.FIRSTID) throw new Error('SDK FirstID non disponible après chargement');
  742.             const firstId = window.FIRSTID.getId ? window.FIRSTID.getId() : null;
  743.             if (!firstId) throw new Error('Aucun firstId disponible');
  744.             logToTest(testNumber, 'info', `FirstID disponible: ${firstId}`);
  745.             logToTest(testNumber, 'info', '--- Test getDeviceId ---');
  746.             if (!window.FIRSTID.getDeviceId) {
  747.                 throw new Error('La méthode getDeviceId n\'est pas disponible dans ce SDK');
  748.             }
  749.             const deviceId = await window.FIRSTID.getDeviceId();
  750.             if (!deviceId) throw new Error('getDeviceId a retourné null ou undefined');
  751.             logToTest(testNumber, 'info', `✓ DeviceId obtenu: ${deviceId}`);
  752.             const deviceIdSecondCall = await window.FIRSTID.getDeviceId();
  753.             if (deviceIdSecondCall !== deviceId) {
  754.                 throw new Error('Le deviceId n\'est pas stable entre les appels');
  755.             }
  756.             logToTest(testNumber, 'info', '✓ DeviceId identique confirmé');
  757.             logToTest(testNumber, 'info', '--- Test getFirstIdEidsObject ---');
  758.             if (!window.FIRSTID.getFirstIdEidsObject) {
  759.                 throw new Error('La méthode getFirstIdEidsObject n\'est pas disponible dans ce SDK');
  760.             }
  761.             const eidsObject = window.FIRSTID.getFirstIdEidsObject();
  762.             if (!eidsObject || !Array.isArray(eidsObject) || eidsObject.length === 0) {
  763.                 throw new Error('getFirstIdEidsObject n\'a pas retourné un tableau valide');
  764.             }
  765.             const eidsEntry = eidsObject[0];
  766.             if (!eidsEntry.source || eidsEntry.source !== 'first-id.fr') {
  767.                 throw new Error(`Source incorrecte: ${eidsEntry.source}, attendu: first-id.fr`);
  768.             }
  769.             if (!eidsEntry.uids || !Array.isArray(eidsEntry.uids) || eidsEntry.uids.length === 0) {
  770.                 throw new Error('uids manquant ou invalide');
  771.             }
  772.             const uidEntry = eidsEntry.uids[0];
  773.             if (uidEntry.atype !== 1) throw new Error(`atype incorrect: ${uidEntry.atype}, attendu: 1`);
  774.             if (!uidEntry.ext || uidEntry.ext.stype !== 'ppuid') {
  775.                 throw new Error(`ext.stype incorrect: ${uidEntry.ext?.stype}, attendu: ppuid`);
  776.             }
  777.             if (uidEntry.id !== firstId) {
  778.                 throw new Error(`id incorrect: ${uidEntry.id}, attendu: ${firstId}`);
  779.             }
  780.             logToTest(testNumber, 'info', '✓ Structure eidsObject valide');
  781.             logToTest(testNumber, 'info', `  - source: ${eidsEntry.source}, atype: ${uidEntry.atype}, ext.stype: ${uidEntry.ext.stype}`);
  782.             setTestStatus(testNumber, 'success', 'Test 8 réussi - getDeviceId et getFirstIdEidsObject validés');
  783.             testState.results[testNumber] = true;
  784.         } catch (error) {
  785.             logToTest(testNumber, 'error', `Erreur détaillée: ${error.message}`);
  786.             setTestStatus(testNumber, 'error', `Test 8 échoué: ${error.message}`);
  787.             testState.results[testNumber] = false;
  788.         } finally {
  789.             teardownConsoleInterceptor();
  790.         }
  791.     }
  792.     async function runTest9() {
  793.         const testNumber = 9;
  794.         setTestStatus(testNumber, 'running', 'Démarrage du Test 9...');
  795.         setupConsoleInterceptor(testNumber);
  796.         const EXPECTED_MASTER_TYPE = 1;
  797.         const SLAVE_FIRST_ID = 'c8f6459136c6469ca43d3838082b94eb';
  798.         try {
  799.             logToTest(testNumber, 'info', '=== Test 9: getMasterFirstId ===');
  800.             deleteCookies();
  801.             logToTest(testNumber, 'info', 'Réinitialisation de la matrice (fingerprints)...');
  802.             await deleteFingerprints(testNumber);
  803.             cleanSdkGlobals();
  804.             configureSdkWindow();
  805.             const domain = window.location.hostname.split('.').slice(-2).join('.');
  806.             document.cookie = `firstid=${SLAVE_FIRST_ID}; path=/; domain=${domain}`;
  807.             logToTest(testNumber, 'info', `Cookie firstid défini avec le slave: ${SLAVE_FIRST_ID}`);
  808.             await loadFirstIdScript(testNumber);
  809.             logToTest(testNumber, 'info', 'Attente de l\'initialisation du SDK...');
  810.             await waitForFirstIdInitialized(testNumber);
  811.             if (!window.FIRSTID) throw new Error('SDK FirstID non disponible après chargement');
  812.             if (!window.FIRSTID.getMasterFirstId) {
  813.                 throw new Error('La méthode getMasterFirstId n\'est pas disponible dans ce SDK');
  814.             }
  815.             const masterFirstId = window.FIRSTID.getId ? window.FIRSTID.getId() : null;
  816.             if (!masterFirstId) throw new Error('Aucun firstId disponible');
  817.             if (masterFirstId !== SLAVE_FIRST_ID) {
  818.                 logToTest(testNumber, 'info', `FirstID actuel (${masterFirstId}) différent du slave (${SLAVE_FIRST_ID})`);
  819.             } else {
  820.                 logToTest(testNumber, 'info', `Master FirstID confirmé: ${masterFirstId}`);
  821.             }
  822.             const firstIdTypeAfter = window.FIRSTID.getIdStruct
  823.                 ? (window.FIRSTID.getIdStruct().t || null)
  824.                 : null;
  825.             if (firstIdTypeAfter !== EXPECTED_MASTER_TYPE) {
  826.                 throw new Error(`Le type du firstId ne correspond pas. Attendu: ${EXPECTED_MASTER_TYPE}, Reçu: ${firstIdTypeAfter}`);
  827.             }
  828.             logToTest(testNumber, 'info', `✓ Type correct: ${firstIdTypeAfter}`);
  829.             if (masterFirstId === SLAVE_FIRST_ID) {
  830.                 throw new Error('Le master firstId est identique au slave firstId');
  831.             }
  832.             logToTest(testNumber, 'info', '✓ Master FirstID différent du slave confirmé');
  833.             const cookieAfter = getCookieValue('firstid');
  834.             if (cookieAfter && cookieAfter === masterFirstId) {
  835.                 logToTest(testNumber, 'info', `✓ Cookie firstid mis à jour avec le master: ${cookieAfter}`);
  836.             }
  837.             logToTest(testNumber, 'info', '=== Résumé du Test 9 ===');
  838.             logToTest(testNumber, 'info', `✓ Slave: ${SLAVE_FIRST_ID} → Master: ${masterFirstId} (type: ${firstIdTypeAfter})`);
  839.             setTestStatus(testNumber, 'success', 'Test 9 réussi - getMasterFirstId validé');
  840.             testState.results[testNumber] = true;
  841.         } catch (error) {
  842.             logToTest(testNumber, 'error', `Erreur détaillée: ${error.message}`);
  843.             setTestStatus(testNumber, 'error', `Test 9 échoué: ${error.message}`);
  844.             testState.results[testNumber] = false;
  845.         } finally {
  846.             teardownConsoleInterceptor();
  847.         }
  848.     }
  849.     function waitForConsent() {
  850.         return new Promise((resolve) => {
  851.             if (!window.__tcfapi) {
  852.                 logToTest(1, 'info', 'TCF API non disponible, passage en mode sans consentement');
  853.                 resolve(true);
  854.                 return;
  855.             }
  856.             window.__tcfapi('addEventListener', 2, (tcData, success) => {
  857.                 if (success && tcData.gdprApplies) {
  858.                     if (tcData.vendor.consents[FIRSTID_VENDOR_ID] &&
  859.                         (tcData.eventStatus === 'useractioncomplete' || tcData.eventStatus === 'tcloaded')) {
  860.                         testState.hasConsent = true;
  861.                         resolve(true);
  862.                     }
  863.                 } else {
  864.                     resolve(true);
  865.                 }
  866.             });
  867.         });
  868.     }
  869.     document.getElementById('startAllTests').addEventListener('click', async function () {
  870.         this.disabled = true;
  871.         resetTestState();
  872.         resetAllTestStatuses();
  873.         testState.suiteStartTime = Date.now();
  874.         logToTest(1, 'info', 'Attente du consentement TCF...');
  875.         await waitForConsent();
  876.         await runTest1();
  877.         if (testState.results[1]) {
  878.             await runTest2();
  879.         }
  880.         await runTest3();
  881.         await runTest4();
  882.         await runTest5();
  883.         if (testState.results[1] || testState.results[2]) {
  884.             await runTest6();
  885.         }
  886.         if (testState.results[1] || testState.results[2]) {
  887.             await runTest7();
  888.         }
  889.         if (testState.results[1] || testState.results[2]) {
  890.             await runTest8();
  891.         }
  892.         if (testState.results[1] || testState.results[2]) {
  893.             await runTest9();
  894.         }
  895.         showGlobalSummary();
  896.         this.disabled = false;
  897.     });
  898. </script>
  899. </body>
  900. </html>