validate live API response contracts
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
{
|
||||
"base": "https://ihaleist.com",
|
||||
"readOnly": true,
|
||||
"checkedAt": "2026-09-06T16:13:35.286Z",
|
||||
"checkedAt": "2026-09-06T16:23:52.207Z",
|
||||
"checks": {
|
||||
"home": {
|
||||
"status": 200,
|
||||
"contentType": "text/html",
|
||||
"headers": {
|
||||
"x-content-type-options": null,
|
||||
"referrer-policy": null,
|
||||
@@ -13,19 +14,30 @@
|
||||
},
|
||||
"health": {
|
||||
"status": 200,
|
||||
"contentType": "application/json; charset=utf-8",
|
||||
"headers": {
|
||||
"x-content-type-options": null,
|
||||
"referrer-policy": null,
|
||||
"permissions-policy": null
|
||||
}
|
||||
},
|
||||
"json": {
|
||||
"ok": true
|
||||
},
|
||||
"apiSuccess": true
|
||||
},
|
||||
"ready": {
|
||||
"status": 404,
|
||||
"contentType": "application/json; charset=utf-8",
|
||||
"headers": {
|
||||
"x-content-type-options": null,
|
||||
"referrer-policy": null,
|
||||
"permissions-policy": null
|
||||
}
|
||||
},
|
||||
"json": {
|
||||
"success": false,
|
||||
"error": "not found"
|
||||
},
|
||||
"apiSuccess": false
|
||||
}
|
||||
},
|
||||
"pass": false,
|
||||
|
||||
@@ -2254,3 +2254,9 @@ Doğrulama: 294 otomatik test, üretim derlemesi ve `git diff --check` başarıl
|
||||
Browser QA Playwright context’i `America/New_York` saat diliminde çalışacak şekilde ayarlandı; buna rağmen İstanbul tarih/saat akışları, günlük bülten, ICS, çıktı ve mobil viewport kontrolleri başarılı. Böylece önceki zaman standardizasyonu yalnızca Türkiye yerel cihazında değil, farklı cihaz saat diliminde de sınanıyor.
|
||||
|
||||
Doğrulama: browserTimezone `America/New_York`, mobil viewport 390 px ve yatay taşma yok; tüm kabul kontrolleri başarılı.
|
||||
|
||||
### 2026-09-06 · Canlı probe JSON sözleşmesi
|
||||
|
||||
Canlı drift probe’u artık API yanıt gövdesini de doğruluyor: `/api/health` için `ok:true`, `/api/ready` için `success:true` ve JSON içerik türü aranıyor. Böylece HTTP 200 dönen SPA/ara hata sayfaları sağlıklı servis kabul edilmiyor.
|
||||
|
||||
Güncel canlı sonuçta health `ok:true` olsa da readiness `404` ve güvenlik başlıkları eksik olduğu için probe başarısız kaldı; kanıt `qa-live-runtime.json` içinde.
|
||||
|
||||
@@ -8,15 +8,22 @@ const timeoutMs = 15_000;
|
||||
const requiredHeaders = ['x-content-type-options', 'referrer-policy', 'permissions-policy'];
|
||||
const checks = {};
|
||||
|
||||
async function probe(path) {
|
||||
async function probe(path, successField = null) {
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
||||
try {
|
||||
const response = await fetch(base + path, { signal: controller.signal, redirect: 'manual' });
|
||||
return {
|
||||
const result = {
|
||||
status: response.status,
|
||||
contentType: response.headers.get('content-type'),
|
||||
headers: Object.fromEntries(requiredHeaders.map(name => [name, response.headers.get(name)])),
|
||||
};
|
||||
if (successField) {
|
||||
const raw = await response.text();
|
||||
try { result.json = JSON.parse(raw); } catch { result.jsonError = 'JSON yanıtı ayrıştırılamadı.'; }
|
||||
result.apiSuccess = result.json?.[successField] === true;
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
return { error: error.name === 'AbortError' ? `timeout after ${timeoutMs}ms` : error.message };
|
||||
} finally {
|
||||
@@ -25,15 +32,15 @@ async function probe(path) {
|
||||
}
|
||||
|
||||
checks.home = await probe('/');
|
||||
checks.health = await probe('/api/health');
|
||||
checks.ready = await probe('/api/ready');
|
||||
const missingHeaders = requiredHeaders.filter(name => checks.home?.headers?.[name] == null || checks.health?.headers?.[name] == null);
|
||||
checks.health = await probe('/api/health', 'ok');
|
||||
checks.ready = await probe('/api/ready', 'success');
|
||||
const missingHeaders = requiredHeaders.filter(name => [checks.home, checks.health, checks.ready].some(check => check?.headers?.[name] == null));
|
||||
const report = {
|
||||
base,
|
||||
readOnly: true,
|
||||
checkedAt: new Date().toISOString(),
|
||||
checks,
|
||||
pass: checks.home?.status === 200 && checks.health?.status === 200 && checks.ready?.status === 200 && missingHeaders.length === 0,
|
||||
pass: checks.home?.status === 200 && checks.health?.status === 200 && checks.health.apiSuccess === true && checks.ready?.status === 200 && checks.ready.apiSuccess === true && missingHeaders.length === 0,
|
||||
missingHeaders,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user