openvibers/openvibe.extensions Commits

Coupons Helper: a clear message when you report on a code you submitted

OP OpenVibers committed 23 Sept 2026 · e9fd24f4c1 · 3 files, +50 −2

OpenVibe.Coupons refuses a report from the person who submitted the code (or evidence for it) with
403 report.own_submission (Coupons 870c389). The popup showed "Something went wrong. Try again
later." for it; it now says "You can’t report on a code you submitted." test/messages.test.js
drives the popup controller against the stub API for that refusal and the others.

Changes

ddiff --git a/browser/lib/controller.js b/browser/lib/controller.js
iindex 51db7b4..3498141 100644
---- a/browser/lib/controller.js
++++ b/browser/lib/controller.js
@@@ -31,6 +31,7 @@
if (code === 'auth.required') return 'Connect the extension in the settings to report.';
if (code === 'report.rate_limited' || code === 'lookup.rate_limited' || (err && err.status === 429)) return 'Too many requests right now. Try again in a minute.';
if (code === 'coupon.not_active') return 'This code is no longer in active results.';
++ if (code === 'report.own_submission') return 'You can’t report on a code you submitted.';
if (code === 'network.timeout' || code === 'network.error') return 'Could not reach OpenVibe.Coupons.';
return 'Something went wrong. Try again later.';
}
ddiff --git a/test/helpers/harness.js b/test/helpers/harness.js
iindex 69e5267..64364b3 100644
---- a/test/helpers/harness.js
++++ b/test/helpers/harness.js
@@@ -21,6 +21,7 @@ const COUPON = {
const GOOD_TOKEN = `cpx_${'a'.repeat(43)}`;
const REVOKED_TOKEN = `cpx_${'r'.repeat(43)}`;
const NO_REPORT_TOKEN = `cpx_${'n'.repeat(43)}`;
++const SUBMITTER_TOKEN = `cpx_${'s'.repeat(43)}`; // the person who submitted COUPON
/** A stub of the Coupons API with the behaviour the extension relies on. */
function startStub({ delayMs = 0 } = {}) {
@@@ -37,7 +38,7 @@ function startStub({ delayMs = 0 } = {}) {
}, delayMs);
const auth = req.headers.authorization || '';
if (auth === `Bearer ${REVOKED_TOKEN}`) return send(401, { code: 'token.revoked', detail: 'disconnected' });
-- if (auth && ![`Bearer ${GOOD_TOKEN}`, `Bearer ${NO_REPORT_TOKEN}`].includes(auth)) return send(401, { code: 'token.invalid', detail: 'unknown' });
++ if (auth && ![`Bearer ${GOOD_TOKEN}`, `Bearer ${NO_REPORT_TOKEN}`, `Bearer ${SUBMITTER_TOKEN}`].includes(auth)) return send(401, { code: 'token.invalid', detail: 'unknown' });
const u = new URL(req.url, 'http://x');
if (req.method === 'GET' && u.pathname === '/api/v1/merchants/resolve') {
const host = u.searchParams.get('host');
@@@ -50,6 +51,7 @@ function startStub({ delayMs = 0 } = {}) {
if (req.method === 'POST' && u.pathname === `/api/v1/coupons/${COUPON.id}/report`) {
if (!auth) return send(401, { code: 'auth.required' });
if (auth === `Bearer ${NO_REPORT_TOKEN}`) return send(403, { code: 'token.scope' });
++ if (auth === `Bearer ${SUBMITTER_TOKEN}`) return send(403, { code: 'report.own_submission', detail: 'you submitted this code; its status comes from other people\'s reports' });
return send(201, { accepted: true, deduplicated: false, corrected: false, coupon: { ...COUPON, status: 'reported_working', confidence: 0.67 } });
}
return send(404, { code: 'route.not_found' });
@@@ -88,4 +90,4 @@ function fakeExt({ url = null, token = null, hasPermission = true } = {}) {
};
}
--module.exports = { check, done, startStub, recordingFetch, fakeExt, MERCHANT, COUPON, GOOD_TOKEN, REVOKED_TOKEN, NO_REPORT_TOKEN };
++module.exports = { check, done, startStub, recordingFetch, fakeExt, MERCHANT, COUPON, GOOD_TOKEN, REVOKED_TOKEN, NO_REPORT_TOKEN, SUBMITTER_TOKEN };
ddiff --git a/test/messages.test.js b/test/messages.test.js
nnew file mode 100644
iindex 0000000..9b057e6
---- /dev/null
++++ b/test/messages.test.js
@@@ -0,0 +1,45 @@
++'use strict';
++/**
++ * What the popup says when a report is refused: each refusal the Coupons API can give a report has
++ * its own clear message, never the generic "Something went wrong".
++ */
++const assert = require('assert');
++const host = require('../browser/lib/host');
++const { createApiClient } = require('../browser/lib/api');
++const { createPlatform } = require('../browser/lib/platform');
++const { createController, messageFor } = require('../browser/lib/controller');
++const config = require('../browser/lib/config');
++const { check, done, startStub, fakeExt, COUPON, GOOD_TOKEN, NO_REPORT_TOKEN, SUBMITTER_TOKEN } = require('./helpers/harness');
++
++const GENERIC = messageFor(null);
++
++(async () => {
++ const stub = await startStub();
++ const popup = (token) => {
++ const platform = createPlatform(fakeExt({ url: 'https://acme-outdoor.com/', token }), { ...config, API_ORIGIN: stub.origin });
++ const api = createApiClient({ origin: stub.origin, fetch, getToken: platform.storage.getToken });
++ return createController({ api, platform, host });
++ };
++
++ await check('reporting on a code you submitted (403 report.own_submission) says so', async () => {
++ const r = await popup(SUBMITTER_TOKEN).report(COUPON.id, 'worked');
++ assert.strictEqual(r.ok, false);
++ assert.strictEqual(r.code, 'report.own_submission');
++ assert.strictEqual(r.message, 'You can’t report on a code you submitted.');
++ assert.notStrictEqual(r.message, GENERIC);
++ });
++
++ await check('the other report refusals keep their own messages; a successful report is thanked', async () => {
++ const scope = await popup(NO_REPORT_TOKEN).report(COUPON.id, 'worked');
++ assert.strictEqual(scope.code, 'token.scope');
++ assert.notStrictEqual(scope.message, GENERIC);
++ const ok = await popup(GOOD_TOKEN).report(COUPON.id, 'worked');
++ assert.strictEqual(ok.ok, true);
++ for (const code of ['report.own_submission', 'report.rate_limited', 'coupon.not_active', 'auth.required', 'token.revoked']) {
++ assert.notStrictEqual(messageFor({ code }), GENERIC, code);
++ }
++ });
++
++ await stub.close();
++ done();
++})();