game-maker / suite (push) Failing after 10m23s
Typing "variable" into the node palette landed on `Run behavior`, because the filter weighed label, type and description alike and then sorted by category. `searchRank` in `src/ui/search.ts` now ranks a match: exact label or type, then prefix, then label, then type, and only last a hit that lives in the description alone. Category and alphabet order within a rank. The searchable `Menu` uses the same function, so searching means the same thing everywhere. The `+` menu grew to fifteen entries in declaration order. It is built in two alphabetical groups now -- the types that go into a scene, then the ones that stay in the library -- with a separator between them, the split `isPlaceableType` already draws. `ASSET_TYPES` itself stays untouched: it is also the serialisation and check order. A search flattens the groups and drops the lines. Popups were capped at fixed heights (320 menu, 260 palette, 340 pickers) while the canvas had room to spare. `Popup.roomFor()` measures its own chrome and takes the window height minus a tenth at each end. Placement clamps asymmetrically: the bottom margin is enforced, the top is only a budget, so a menu anchored near the top stays at its button instead of being pushed off it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
38 lines
1.4 KiB
TypeScript
38 lines
1.4 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { searchRank } from '../../src/ui/search';
|
|
|
|
describe('searchRank', () => {
|
|
const fields = ['Set variable', 'setvariable', 'Writes a value into a variable'];
|
|
|
|
it('ranks everything alike when nothing was typed', () => {
|
|
expect(searchRank('', fields)).toBe(0);
|
|
expect(searchRank('', ['anything at all'])).toBe(0);
|
|
});
|
|
|
|
it('answers -1 when no field contains the query', () => {
|
|
expect(searchRank('collider', fields)).toBe(-1);
|
|
});
|
|
|
|
it('puts an exact hit first, whichever field it came from', () => {
|
|
expect(searchRank('set variable', fields)).toBe(0);
|
|
expect(searchRank('setvariable', fields)).toBe(0);
|
|
});
|
|
|
|
it('prefers a prefix over a substring, and the label over the type', () => {
|
|
const prefix = searchRank('set', fields);
|
|
const substring = searchRank('variable', fields);
|
|
expect(prefix).toBeGreaterThan(0);
|
|
expect(prefix).toBeLessThan(substring);
|
|
});
|
|
|
|
it('ranks a description-only hit behind every hit on the label', () => {
|
|
const description = searchRank('writes', fields);
|
|
expect(description).toBeGreaterThan(searchRank('variable', fields));
|
|
});
|
|
|
|
it('takes the best field, not the first that matches', () => {
|
|
// "value" sits in the description only, "Set" in the label -- a query in both takes the label.
|
|
expect(searchRank('set', ['Set value', 'setvalue', 'Set a value'])).toBe(1);
|
|
});
|
|
});
|