buildChatGptUrl and its fitToBudget helpers have had no production caller since prepareAction took over routing; the 2026-10-05 plan kept them only for existing tests until then. They also shortened silently, against the ask-before-shortening rule, so they were a trap to reuse. Port the tests that guard live code onto applyTemplate and serializePrompt, including the $&, $`, $' and $$ regressions (checked to fail against the string-replacement form), and cover prepareAction's whole-word cut, which nothing tested before. Also drop getContext's inputType password check. menus.OnClickData has no inputType, so it never fired; Firefox already withholds password fields from selectionText via mozIsTextField(true) in SelectionUtils (bug 565717). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
52 lines
3.5 KiB
JavaScript
52 lines
3.5 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { DEFAULT_SETTINGS } from '../lib/defaults.js';
|
|
const { prepareAction } = await import('../lib/prepare-action.js').catch(()=>({}));
|
|
const req = (overrides={}) => ({actionId:'ask',source:'Hello',settings:{...DEFAULT_SETTINGS},...overrides});
|
|
test('ready actions preserve source and hints, translation asks only when needed', () => {
|
|
assert.equal(typeof prepareAction, 'function');
|
|
assert.equal(prepareAction(req()).url, 'https://chatgpt.com/?q=Hello');
|
|
assert.equal(prepareAction(req({actionId:'translate'})).kind,'language');
|
|
assert.match(new URL(prepareAction(req({actionId:'translate',language:'Spanish'})).url).searchParams.get('q'),/Spanish/);
|
|
assert.equal(prepareAction(req({actionId:'translate',settings:{...DEFAULT_SETTINGS,translationMode:'preferred',translationLanguage:'Spanish'}})).kind,'ready');
|
|
assert.equal(prepareAction(req({source:''})).url,'https://chatgpt.com/');
|
|
assert.equal(prepareAction(req({actionId:'debug',source:''})).kind,'error');
|
|
assert.equal(prepareAction(req({actionId:'bogus'})).kind,'error');
|
|
});
|
|
test('URLs are validated and preserved whole, never shortened', () => {
|
|
assert.equal(typeof prepareAction, 'function');
|
|
for (const source of ['javascript:alert(1)','about:config','ftp://example.com','https://user:pass@example.com','not a url','https://example.com/?q='+'x'.repeat(9000)]) {
|
|
assert.equal(prepareAction(req({actionId:'ask-link',source})).kind,'error',source.slice(0,40));
|
|
}
|
|
const source='https://example.com/?q=a%20b&x=1#part';
|
|
const out=prepareAction(req({actionId:'review-link',source}));
|
|
assert.equal(out.kind,'ready');
|
|
assert.ok(new URL(out.url).searchParams.get('q').endsWith(source));
|
|
});
|
|
test('shortened selections end on a whole word and decode cleanly', () => {
|
|
assert.equal(typeof prepareAction, 'function');
|
|
const out=prepareAction(req({source:'lorem ipsum '.repeat(2000)}));
|
|
assert.equal(out.kind,'shortened');
|
|
const words=new URL(out.url).searchParams.get('q').replace('[Selected text shortened]','').trim().split(/\s+/);
|
|
assert.ok(words.length>1);
|
|
for (const word of words) assert.ok(word==='lorem'||word==='ipsum',`cut mid-word: ${word}`);
|
|
const emoji=prepareAction(req({source:'😀 '.repeat(9000)}));
|
|
assert.equal(emoji.kind,'shortened');
|
|
assert.doesNotThrow(()=>decodeURIComponent(new URL(emoji.url).search.slice(1)));
|
|
});
|
|
test('long selections preserve instructions, repetition and Unicode with explicit consent', () => {
|
|
assert.equal(typeof prepareAction, 'function');
|
|
const settings={...DEFAULT_SETTINGS,promptTemplate:'START {query} AGAIN {query} END',temporaryChat:true,webSearch:true};
|
|
const out=prepareAction(req({source:'😀 word '.repeat(4000),settings}));
|
|
assert.equal(out.kind,'shortened');
|
|
assert.ok(out.url.length<=8000);
|
|
const q=new URL(out.url).searchParams.get('q');
|
|
assert.ok(q.startsWith('START '));assert.ok(q.includes(' END'));assert.ok(q.includes('[Selected text shortened]'));
|
|
assert.equal(q.match(/START (.*?) AGAIN/s)[1],q.match(/AGAIN (.*?) END/s)[1]);
|
|
assert.equal(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/u.test(q),false);
|
|
assert.equal(new URL(out.url).searchParams.get('hints'),'search');
|
|
assert.equal(prepareAction(req({settings:{...settings,promptTemplate:'x'.repeat(9000)}})).kind,'error');
|
|
const translated=prepareAction(req({actionId:'translate',language:'Spanish',source:'x'.repeat(20000)}));
|
|
assert.equal(translated.kind,'shortened');assert.match(new URL(translated.url).searchParams.get('q'), /Spanish/);
|
|
});
|