Spaces:
Running
Running
test: pin the share-URL routing rule so avatarimg can never return to /share/p/
Browse files
scripts/test-avatar-interiors.mjs
CHANGED
|
@@ -5,10 +5,18 @@
|
|
| 5 |
* still renders, it just renders at the wrong size or without the ring, and
|
| 6 |
* nothing throws. These assert the geometry and the ordering, not just "no
|
| 7 |
* crash".
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
*/
|
| 9 |
import assert from 'node:assert/strict';
|
| 10 |
import { mergeResults } from '../src/merge.js';
|
| 11 |
import { foldText, searchAvatarInteriors } from '../src/avatar-interiors.js';
|
|
|
|
| 12 |
|
| 13 |
let passed = 0, failed = 0;
|
| 14 |
const test = (name, fn) => {
|
|
@@ -56,6 +64,68 @@ test('a query too short to be meaningful is rejected', () => {
|
|
| 56 |
assert.equal(searchAvatarInteriors('a', items).length, 0);
|
| 57 |
});
|
| 58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
console.log('\nfeatured tiles');
|
| 60 |
// ──────────────────────────────────────────────────────────────────────────
|
| 61 |
|
|
@@ -214,4 +284,4 @@ test('fewer than ten new photographs still all ring', () => {
|
|
| 214 |
});
|
| 215 |
|
| 216 |
console.log(`\n${passed} passed, ${failed} failed`);
|
| 217 |
-
process.exit(failed ? 1 : 0);
|
|
|
|
| 5 |
* still renders, it just renders at the wrong size or without the ring, and
|
| 6 |
* nothing throws. These assert the geometry and the ordering, not just "no
|
| 7 |
* crash".
|
| 8 |
+
*
|
| 9 |
+
* The share-URL block is here for the same reason, and it is deliberately
|
| 10 |
+
* Node-only. The browser copy of this rule lives in dist/assets/share-fix.js as
|
| 11 |
+
* a string regex, because it has to run against the served bundle before a
|
| 12 |
+
* rebuild; the routing decision itself lives in src/assets.js. These tests pin
|
| 13 |
+
* the src/ half so the two cannot drift apart silently, and the browser half is
|
| 14 |
+
* asserted separately in scripts/test-neon-ui.mjs.
|
| 15 |
*/
|
| 16 |
import assert from 'node:assert/strict';
|
| 17 |
import { mergeResults } from '../src/merge.js';
|
| 18 |
import { foldText, searchAvatarInteriors } from '../src/avatar-interiors.js';
|
| 19 |
+
import { shareURL } from '../src/assets.js';
|
| 20 |
|
| 21 |
let passed = 0, failed = 0;
|
| 22 |
const test = (name, fn) => {
|
|
|
|
| 64 |
assert.equal(searchAvatarInteriors('a', items).length, 0);
|
| 65 |
});
|
| 66 |
|
| 67 |
+
console.log('\nshare URLs');
|
| 68 |
+
// ──────────────────────────────────────────────────────────────────────────
|
| 69 |
+
|
| 70 |
+
const STUDIO = 'https://bep40-vai-avatar.hf.space';
|
| 71 |
+
const broken = 'https://bep40-vai-avatar.hf.space/share/p/avatarimg%3Ab68dc779370dc70e';
|
| 72 |
+
const fixed = `${STUDIO}/share/i/b68dc779370dc70e`;
|
| 73 |
+
|
| 74 |
+
test('the reported broken URL is now the interior route', () => {
|
| 75 |
+
// The exact address from the report. `avatarimg:` is a namespace for
|
| 76 |
+
// de-duplication, not a catalogue identity, so /share/p/ resolved to nothing
|
| 77 |
+
// and vai-avatar answered "Not Found" for every interior photograph.
|
| 78 |
+
assert.equal(shareURL({ avatarImageId: 'b68dc779370dc70e', sku: 'avatarimg:b68dc779370dc70e' }), fixed);
|
| 79 |
+
});
|
| 80 |
+
|
| 81 |
+
test('the bug is reproducible against the old logic', () => {
|
| 82 |
+
// Pins what the fix is fixing, so the assertion above cannot pass for an
|
| 83 |
+
// unrelated reason. Without the avatarImageId branch, `sku` wins and the link
|
| 84 |
+
// is the dead one -- byte-identical to the reported URL.
|
| 85 |
+
const photo = { sku: 'avatarimg:b68dc779370dc70e' };
|
| 86 |
+
const oldRoute = `${STUDIO}/share/p/${encodeURIComponent(photo.sku)}`;
|
| 87 |
+
assert.equal(oldRoute, broken, 'the reported URL must be what the old routing produced');
|
| 88 |
+
assert.notEqual(shareURL(photo), oldRoute, 'shareURL still routes an avatarimg sku to /share/p/');
|
| 89 |
+
});
|
| 90 |
+
|
| 91 |
+
test('an interior is routed even when it has lost avatarImageId', () => {
|
| 92 |
+
// merge.js rewrites `id` into a namespaced tile key, so a record can arrive
|
| 93 |
+
// carrying the sku but not the original field. The prefix is unwrapped rather
|
| 94 |
+
// than treated as an identity, which is what this fallback exists for.
|
| 95 |
+
assert.equal(shareURL({ sku: 'avatarimg:b68dc779370dc70e' }), fixed);
|
| 96 |
+
});
|
| 97 |
+
|
| 98 |
+
test('an empty avatarimg prefix yields no share URL at all', () => {
|
| 99 |
+
// /share/i/ with nothing after it is its own 404. Returning null lets the
|
| 100 |
+
// caller omit the button rather than render a dead link.
|
| 101 |
+
assert.equal(shareURL({ sku: 'avatarimg:' }), null);
|
| 102 |
+
assert.equal(shareURL({ avatarImageId: ' ' }), null);
|
| 103 |
+
});
|
| 104 |
+
|
| 105 |
+
test('a real product still routes to /share/p/', () => {
|
| 106 |
+
// The fix must not disturb the route that works. A product keeps its slug, and
|
| 107 |
+
// /share/p/ resolves all three identity forms.
|
| 108 |
+
assert.equal(shareURL({ sku: 'MH800TC' }), `${STUDIO}/share/p/MH800TC`);
|
| 109 |
+
assert.equal(
|
| 110 |
+
shareURL({ sku: 'MH800TC', slug: 'mh800tc-malloca-may-hut-mui-gan-tu-am-tu-80cm' }),
|
| 111 |
+
`${STUDIO}/share/p/mh800tc-malloca-may-hut-mui-gan-tu-am-tu-80cm`,
|
| 112 |
+
'the slug must still win over the sku',
|
| 113 |
+
);
|
| 114 |
+
});
|
| 115 |
+
|
| 116 |
+
test('a baked interior without a sku keeps its own route', () => {
|
| 117 |
+
// No sku at all: the id branch is what answers, and it must not be captured by
|
| 118 |
+
// the avatarimg fallback.
|
| 119 |
+
assert.equal(shareURL({ id: 'a1b2c3d4e5' }), `${STUDIO}/share/i/a1b2c3d4e5`);
|
| 120 |
+
});
|
| 121 |
+
|
| 122 |
+
test('a record with nothing to share returns null', () => {
|
| 123 |
+
assert.equal(shareURL(null), null);
|
| 124 |
+
assert.equal(shareURL(undefined), null);
|
| 125 |
+
assert.equal(shareURL({}), null);
|
| 126 |
+
assert.equal(shareURL('nope'), null);
|
| 127 |
+
});
|
| 128 |
+
|
| 129 |
console.log('\nfeatured tiles');
|
| 130 |
// ──────────────────────────────────────────────────────────────────────────
|
| 131 |
|
|
|
|
| 284 |
});
|
| 285 |
|
| 286 |
console.log(`\n${passed} passed, ${failed} failed`);
|
| 287 |
+
process.exit(failed ? 1 : 0);
|