|
| 1 | +import { describe, expect, test } from 'vitest' |
| 2 | +import { assetUrlRE } from '../../plugins/asset' |
| 3 | + |
| 4 | +describe('wasm plugin assetUrlRE usage', () => { |
| 5 | + // Regression test: assetUrlRE has the /g flag, which makes .test() |
| 6 | + // stateful via lastIndex. When the wasm plugin called assetUrlRE.test() |
| 7 | + // on consecutive asset URLs without resetting lastIndex, the second call |
| 8 | + // would fail because lastIndex was already past the end of the string. |
| 9 | + // This caused a non-deterministic bug where ~half of wasm files would |
| 10 | + // miss the __VITE_ASSET__ -> __VITE_WASM_INIT__ replacement in SSR |
| 11 | + // builds, leading to ENOENT errors at runtime. |
| 12 | + test('assetUrlRE.test() fails on second call without lastIndex reset', () => { |
| 13 | + const url1 = '__VITE_ASSET__abc123__' |
| 14 | + const url2 = '__VITE_ASSET__def456__' |
| 15 | + |
| 16 | + // Simulate the bug: two consecutive .test() calls without resetting lastIndex |
| 17 | + assetUrlRE.lastIndex = 0 |
| 18 | + expect(assetUrlRE.test(url1)).toBe(true) |
| 19 | + // After the first successful match, lastIndex is advanced past the string |
| 20 | + expect(assetUrlRE.lastIndex).toBeGreaterThan(0) |
| 21 | + // The second call fails because lastIndex > url2.length |
| 22 | + expect(assetUrlRE.test(url2)).toBe(false) |
| 23 | + |
| 24 | + // Clean up |
| 25 | + assetUrlRE.lastIndex = 0 |
| 26 | + }) |
| 27 | + |
| 28 | + test('assetUrlRE.test() succeeds on consecutive calls with lastIndex reset', () => { |
| 29 | + const url1 = '__VITE_ASSET__abc123__' |
| 30 | + const url2 = '__VITE_ASSET__def456__' |
| 31 | + |
| 32 | + assetUrlRE.lastIndex = 0 |
| 33 | + expect(assetUrlRE.test(url1)).toBe(true) |
| 34 | + |
| 35 | + // The fix: reset lastIndex before the next call |
| 36 | + assetUrlRE.lastIndex = 0 |
| 37 | + expect(assetUrlRE.test(url2)).toBe(true) |
| 38 | + |
| 39 | + // Clean up |
| 40 | + assetUrlRE.lastIndex = 0 |
| 41 | + }) |
| 42 | +}) |
0 commit comments