corentin_wakdo/tests/js/stock-thresholds.test.js
Imugiii fce6dae428
All checks were successful
CI / secret-scan (push) Successful in 19s
CI / php-lint (push) Successful in 43s
CI / static-tests (push) Successful in 1m46s
CI / js-tests (push) Successful in 48s
CI / secret-scan (pull_request) Successful in 29s
CI / php-lint (pull_request) Successful in 44s
CI / static-tests (pull_request) Successful in 1m22s
CI / js-tests (pull_request) Successful in 47s
feat(stock): reglage rapide capacite + seuils depuis la page Stock (modale + endpoint dedie)
2026-06-25 12:27:48 +00:00

116 lines
5.1 KiB
JavaScript

/*
* Tests du reglage rapide des seuils de stock (F13) du back-office (node:test + jsdom).
*
* Couvre la logique testable du module : pre-remplissage de la modale depuis les
* data-attributes du bouton + pointage de l'action POST sur l'id, ouverture/fermeture,
* et le garde-fou client validate() (capacite >= 1, % 0-100, critique < alerte strict).
* La modale est rendue serveur (VRAI form POST) ; le module n'ajoute pas de fetch.
*/
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { JSDOM } from 'jsdom';
// stock-thresholds.js est du CommonJS (admin = racine CommonJS) ; import par defaut.
import stockThresholds from '../../src/public/admin/assets/js/stock-thresholds.js';
function setup() {
const dom = new JSDOM(
'<!DOCTYPE html><html><body>' +
'<button data-threshold-open data-id="7" data-name="Buns" ' +
' data-capacity="200" data-low="15" data-critical="5">Regler les seuils</button>' +
'<div class="pin-modal-overlay" data-threshold-modal>' +
' <form method="post" action="" data-threshold-form>' +
' <input type="hidden" name="_csrf" value="tok">' +
' <input type="number" id="th-capacity" name="stock_capacity">' +
' <input type="number" id="th-low" name="low_stock_pct">' +
' <input type="number" id="th-critical" name="critical_stock_pct">' +
' <p data-threshold-error hidden></p>' +
' <button type="button" data-threshold-cancel>Annuler</button>' +
' <button type="submit">Enregistrer les seuils</button>' +
' </form>' +
'</div>' +
'</body></html>',
);
return dom;
}
function fire(dom, el, type) {
el.dispatchEvent(new dom.window.Event(type, { cancelable: true, bubbles: true }));
}
test('validate accepte une configuration coherente et rejette les cas evidents', () => {
// Coherent.
assert.equal(stockThresholds.validate('200', '15', '5'), null);
// Capacite < 1.
assert.match(stockThresholds.validate('0', '15', '5'), /capacite/i);
// Pourcentage hors 0-100.
assert.match(stockThresholds.validate('100', '120', '5'), /alerte/i);
assert.match(stockThresholds.validate('100', '15', '200'), /critique/i);
// Critique non strictement inferieur a l'alerte.
assert.match(stockThresholds.validate('100', '10', '10'), /strictement inferieur/i);
// Saisies non entieres refusees (miroir de ctype_digit cote serveur).
assert.notEqual(stockThresholds.validate('', '15', '5'), null);
assert.notEqual(stockThresholds.validate('10.5', '15', '5'), null);
});
test('le clic sur un bouton pre-remplit la modale et pointe l action POST sur l id', () => {
const dom = setup();
const doc = dom.window.document;
stockThresholds.init(doc);
fire(dom, doc.querySelector('[data-threshold-open]'), 'click');
const overlay = doc.querySelector('[data-threshold-modal]');
assert.equal(overlay.classList.contains('open'), true);
assert.equal(doc.querySelector('[data-threshold-form]').getAttribute('action'), '/admin/ingredients/7/thresholds');
assert.equal(doc.getElementById('th-capacity').value, '200');
assert.equal(doc.getElementById('th-low').value, '15');
assert.equal(doc.getElementById('th-critical').value, '5');
});
test('soumettre une configuration incoherente bloque le POST et affiche l erreur', () => {
const dom = setup();
const doc = dom.window.document;
stockThresholds.init(doc);
fire(dom, doc.querySelector('[data-threshold-open]'), 'click');
// Critique >= alerte : le garde-fou client doit annuler la soumission.
doc.getElementById('th-critical').value = '15';
const form = doc.querySelector('[data-threshold-form]');
const evt = new dom.window.Event('submit', { cancelable: true, bubbles: true });
form.dispatchEvent(evt);
assert.equal(evt.defaultPrevented, true);
assert.equal(doc.querySelector('[data-threshold-error]').hidden, false);
});
test('soumettre une configuration coherente laisse le form POST partir', () => {
const dom = setup();
const doc = dom.window.document;
stockThresholds.init(doc);
fire(dom, doc.querySelector('[data-threshold-open]'), 'click');
const form = doc.querySelector('[data-threshold-form]');
const evt = new dom.window.Event('submit', { cancelable: true, bubbles: true });
form.dispatchEvent(evt);
// Valeurs pre-remplies coherentes (200/15/5) : pas de blocage client (POST reel).
assert.equal(evt.defaultPrevented, false);
});
test('Annuler ferme la modale', () => {
const dom = setup();
const doc = dom.window.document;
stockThresholds.init(doc);
fire(dom, doc.querySelector('[data-threshold-open]'), 'click');
assert.equal(doc.querySelector('[data-threshold-modal]').classList.contains('open'), true);
fire(dom, doc.querySelector('[data-threshold-cancel]'), 'click');
assert.equal(doc.querySelector('[data-threshold-modal]').classList.contains('open'), false);
});
test('init sans modale (role sans stock.manage) ne plante pas', () => {
const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
assert.doesNotThrow(() => stockThresholds.init(dom.window.document));
});