Changeset 0.28.4 (#190)
This commit is contained in:
128
surfaces/icd-test-runner/js/crud/notifications.js
Normal file
128
surfaces/icd-test-runner/js/crud/notifications.js
Normal file
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* ICD Test Runner — CRUD: Notifications
|
||||
* Full preference lifecycle + notification endpoint error paths.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
var T = window.ICD;
|
||||
if (!T) return;
|
||||
if (!T.crud) T.crud = {};
|
||||
|
||||
T.crud.notifications = async function (testTag) {
|
||||
|
||||
// ── Preference: Set ──
|
||||
await T.test('crud', 'notifications', 'PUT /notifications/preferences/:type (set)', async function () {
|
||||
var d = await T.apiPut('/notifications/preferences/kb.ready', {
|
||||
in_app: true, email: true
|
||||
});
|
||||
T.assert(typeof d === 'object', 'expected object');
|
||||
T.assert(d.type === 'kb.ready', 'type should be kb.ready, got: ' + d.type);
|
||||
T.assert(d.in_app === true, 'in_app should be true');
|
||||
T.assert(d.email === true, 'email should be true');
|
||||
});
|
||||
|
||||
// ── Preference: Read back via list ──
|
||||
await T.test('crud', 'notifications', 'GET /notifications/preferences (round-trip)', async function () {
|
||||
var d = await T.apiGet('/notifications/preferences');
|
||||
T.assertHasKey(d, 'data', 'preferences envelope');
|
||||
T.assert(Array.isArray(d.data), 'data should be array');
|
||||
var found = d.data.find(function (p) { return p.type === 'kb.ready'; });
|
||||
T.assert(found, 'kb.ready preference should be in list');
|
||||
T.assert(found.in_app === true, 'in_app should be true');
|
||||
T.assert(found.email === true, 'email should be true');
|
||||
});
|
||||
|
||||
// ── Preference: Partial update ──
|
||||
await T.test('crud', 'notifications', 'PUT /notifications/preferences/:type (partial update)', async function () {
|
||||
var d = await T.apiPut('/notifications/preferences/kb.ready', {
|
||||
email: false
|
||||
});
|
||||
T.assert(d.in_app === true, 'in_app should remain true after partial update');
|
||||
T.assert(d.email === false, 'email should be false after partial update');
|
||||
});
|
||||
|
||||
// ── Preference: Wildcard ──
|
||||
await T.test('crud', 'notifications', 'PUT /notifications/preferences/* (wildcard)', async function () {
|
||||
var d = await T.apiPut('/notifications/preferences/*', {
|
||||
in_app: false, email: true
|
||||
});
|
||||
T.assert(d.type === '*', 'type should be *, got: ' + d.type);
|
||||
T.assert(d.in_app === false, 'in_app should be false');
|
||||
T.assert(d.email === true, 'email should be true');
|
||||
});
|
||||
|
||||
// ── Preference: Delete + verify removed ──
|
||||
await T.test('crud', 'notifications', 'DELETE /notifications/preferences/:type (reset)', async function () {
|
||||
await T.safeDelete('/notifications/preferences/kb.ready');
|
||||
var d = await T.apiGet('/notifications/preferences');
|
||||
var found = (d.data || []).find(function (p) { return p.type === 'kb.ready'; });
|
||||
T.assert(!found, 'kb.ready should be removed after delete');
|
||||
});
|
||||
|
||||
// ── Preference: Idempotent delete ──
|
||||
await T.test('crud', 'notifications', 'DELETE /notifications/preferences/:type (idempotent)', async function () {
|
||||
await T.safeDelete('/notifications/preferences/nonexistent.type');
|
||||
});
|
||||
|
||||
// ── Cleanup wildcard preference ──
|
||||
await T.test('crud', 'notifications', 'DELETE /notifications/preferences/* (cleanup)', async function () {
|
||||
await T.safeDelete('/notifications/preferences/*');
|
||||
});
|
||||
|
||||
// ── Notification list: envelope shape ──
|
||||
await T.test('crud', 'notifications', 'GET /notifications (envelope shape)', async function () {
|
||||
var d = await T.apiGet('/notifications');
|
||||
T.assertHasKey(d, 'data', 'notifications envelope');
|
||||
T.assertHasKey(d, 'total', 'notifications total');
|
||||
T.assertHasKey(d, 'limit', 'notifications limit');
|
||||
T.assertHasKey(d, 'offset', 'notifications offset');
|
||||
T.assert(Array.isArray(d.data), 'data should be array');
|
||||
T.assert(typeof d.total === 'number', 'total should be number');
|
||||
T.assert(typeof d.limit === 'number', 'limit should be number');
|
||||
T.assert(typeof d.offset === 'number', 'offset should be number');
|
||||
});
|
||||
|
||||
// ── Notification list: pagination params ──
|
||||
await T.test('crud', 'notifications', 'GET /notifications?limit=2 (pagination)', async function () {
|
||||
var d = await T.apiGet('/notifications?limit=2&offset=0');
|
||||
T.assert(d.limit === 2, 'limit should be 2, got: ' + d.limit);
|
||||
T.assert(d.offset === 0, 'offset should be 0, got: ' + d.offset);
|
||||
});
|
||||
|
||||
// ── Notification list: unread_only filter ──
|
||||
await T.test('crud', 'notifications', 'GET /notifications?unread_only=true', async function () {
|
||||
var d = await T.apiGet('/notifications?unread_only=true');
|
||||
T.assertHasKey(d, 'data', 'unread envelope');
|
||||
T.assert(Array.isArray(d.data), 'unread data should be array');
|
||||
});
|
||||
|
||||
// ── Unread count: shape ──
|
||||
await T.test('crud', 'notifications', 'GET /notifications/unread-count (shape)', async function () {
|
||||
var d = await T.apiGet('/notifications/unread-count');
|
||||
T.assertHasKey(d, 'count', 'unread-count');
|
||||
T.assert(typeof d.count === 'number', 'count should be number');
|
||||
});
|
||||
|
||||
// ── Mark all read: no-op on empty ──
|
||||
await T.test('crud', 'notifications', 'POST /notifications/mark-all-read (no-op)', async function () {
|
||||
var d = await T.apiPost('/notifications/mark-all-read');
|
||||
T.assertHasKey(d, 'ok', 'mark-all-read');
|
||||
T.assert(d.ok === true, 'ok should be true');
|
||||
});
|
||||
|
||||
// ── Mark read: non-existent → 404 ──
|
||||
await T.test('crud', 'notifications', 'PATCH /notifications/:id/read (not found → 404)', async function () {
|
||||
var token = await T.getAuthToken();
|
||||
var d = await T.authFetch(token, 'PATCH', '/notifications/00000000-0000-0000-0000-000000000000/read');
|
||||
T.assertStatus(d, 404, 'mark read non-existent');
|
||||
});
|
||||
|
||||
// ── Delete: non-existent → 404 ──
|
||||
await T.test('crud', 'notifications', 'DELETE /notifications/:id (not found → 404)', async function () {
|
||||
var token = await T.getAuthToken();
|
||||
var d = await T.authFetch(token, 'DELETE', '/notifications/00000000-0000-0000-0000-000000000000');
|
||||
T.assertStatus(d, 404, 'delete non-existent');
|
||||
});
|
||||
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user