+
Testing with actual Three.js files:
+
+ - three.module.js (${Math.round(threeJs.length/1024)}KB)
+ ${threeCore ? `- three.core.js (${Math.round(threeCore.length/1024)}KB)
` : ''}
+ - OrbitControls.js (${Math.round(orbitControls.length/1024)}KB)
+
+
Starting...
+
+
+ `
+ });
+
+ const filePath = writeTestFile('actual-threejs-test.html', html);
+ console.log('Loading actual Three.js test file:', filePath);
+ await page.goto(`file://${filePath}`);
+
+ // Wait for test to complete
+ await page.waitForFunction(() => window.actualThreeJsTestComplete, { timeout: 15000 });
+
+ // Check results
+ const error = await page.evaluate(() => window.actualThreeJsTestError);
+ const status = await page.evaluate(() => document.getElementById('status')?.textContent);
+
+ console.log('Actual Three.js test results:', { error, status });
+
+ if (error) {
+ console.log('Test failed with error (this may be expected):', error);
+ // Check if it's the expected relative import error
+ if (error.includes('Failed to resolve module specifier')) {
+ console.log('✅ Got expected relative import error - this confirms the issue');
+ expect(error).toContain('Failed to resolve module specifier');
+ } else {
+ throw new Error('Unexpected error: ' + error);
+ }
+ } else {
+ console.log('✅ Test passed - Three.js loaded successfully!');
+ expect(status).toContain('Success!');
+
+ // Check that canvas was created
+ const canvasExists = await page.evaluate(() => !!document.querySelector('#container canvas'));
+ expect(canvasExists).toBe(true);
+ }
+ });
+
+ test('import/export syntax edge cases', async ({ page }) => {
+ const scripts: TestScript[] = [
+ // Empty module with default export
+ {
+ type: 'esm',
+ path: './modules/empty.js',
+ content: `
+ // This module is intentionally empty but exports a default
+ export default null;
+ `
+ },
+ // Module with only side effects
+ {
+ type: 'esm',
+ path: './modules/side-effects.js',
+ content: `
+ console.log('Side effect executed');
+ window.sideEffectRan = true;
+ `
+ },
+ // Module with all export types
+ {
+ type: 'esm',
+ path: './modules/all-exports.js',
+ content: `
+ // Named exports
+ export const namedValue = 'named';
+ export function namedFunction() { return 'named-function'; }
+
+ // Default export
+ const defaultObj = { type: 'default', value: 42 };
+ export default defaultObj;
+
+ // Re-exports
+ export { namedValue as aliasedValue };
+ export { default as defaultAlias } from './empty.js';
+
+ // Star exports (namespace)
+ export * as utils from './utils.js';
+
+ // Aggregate exports
+ export * from './side-effects.js';
+ `
+ },
+ // Utils module for re-exports
+ {
+ type: 'esm',
+ path: './modules/utils.js',
+ content: `
+ export const utility1 = 'util1';
+ export const utility2 = 'util2';
+ export function utilFunction() {
+ return 'utility-function';
+ }
+ `
+ },
+ // Module testing all import types
+ {
+ type: 'esm',
+ path: './main.js',
+ content: `
+ // Import everything as namespace
+ import * as AllExports from './modules/all-exports.js';
+
+ // Import specific named exports
+ import { namedValue, namedFunction, aliasedValue } from './modules/all-exports.js';
+
+ // Import default
+ import defaultImport from './modules/all-exports.js';
+
+ // Import with alias
+ import { namedValue as renamedValue } from './modules/all-exports.js';
+
+ // Side effect import (no bindings)
+ import './modules/side-effects.js';
+
+ // Empty module import
+ import './modules/empty.js';
+
+ // Mixed imports
+ import defaultMixed, { namedValue as mixedNamed, utils } from './modules/all-exports.js';
+
+ window.testEdgeCases = function() {
+ const results = {
+ // Namespace import tests
+ namespaceHasNamed: AllExports.namedValue === 'named',
+ namespaceHasFunction: typeof AllExports.namedFunction === 'function',
+ namespaceHasDefault: AllExports.default.type === 'default',
+ namespaceHasUtils: typeof AllExports.utils === 'object',
+
+ // Named import tests
+ namedValueCorrect: namedValue === 'named',
+ namedFunctionWorks: namedFunction() === 'named-function',
+ aliasedValueCorrect: aliasedValue === 'named',
+ renamedValueCorrect: renamedValue === 'named',
+
+ // Default import tests
+ defaultImportCorrect: defaultImport.type === 'default' && defaultImport.value === 42,
+
+ // Mixed import tests
+ mixedDefaultCorrect: defaultMixed.type === 'default',
+ mixedNamedCorrect: mixedNamed === 'named',
+ mixedUtilsCorrect: utils.utility1 === 'util1',
+
+ // Re-export tests
+ utilsNamespaceWorks: utils.utility1 === 'util1' && utils.utility2 === 'util2',
+ utilsFunctionWorks: utils.utilFunction() === 'utility-function',
+
+ // Side effect tests
+ sideEffectRan: window.sideEffectRan === true,
+
+ // Empty module handling
+ emptyModuleHandled: true // If we get here, empty module didn't break anything
+ };
+
+ console.log('Edge cases test results:', results);
+ return results;
+ };
+ `
+ }
+ ];
+
+ const html = generateTestHtml(scripts, {
+ title: 'Import/Export Edge Cases Test',
+ additionalBody: `
+
+ `
+ });
+ const filePath = writeTestFile('edge-cases-test.html', html);
+ await page.goto(`file://${filePath}`);
+
+ await page.waitForFunction(() => window.edgeCasesTestComplete, { timeout: 10000 });
+
+ const error = await page.evaluate(() => window.edgeCasesError);
+ const results = await page.evaluate(() => window.edgeCasesResults);
+
+ if (error) {
+ throw new Error('Edge cases test failed: ' + error);
+ }
+
+ console.log('Edge cases test results:', results);
+
+ // Verify namespace imports
+ expect(results.namespaceHasNamed).toBe(true);
+ expect(results.namespaceHasFunction).toBe(true);
+ expect(results.namespaceHasDefault).toBe(true);
+ expect(results.namespaceHasUtils).toBe(true);
+
+ // Verify named imports and aliases
+ expect(results.namedValueCorrect).toBe(true);
+ expect(results.namedFunctionWorks).toBe(true);
+ expect(results.aliasedValueCorrect).toBe(true);
+ expect(results.renamedValueCorrect).toBe(true);
+
+ // Verify default imports
+ expect(results.defaultImportCorrect).toBe(true);
+
+ // Verify mixed imports
+ expect(results.mixedDefaultCorrect).toBe(true);
+ expect(results.mixedNamedCorrect).toBe(true);
+ expect(results.mixedUtilsCorrect).toBe(true);
+
+ // Verify re-exports and namespace exports
+ expect(results.utilsNamespaceWorks).toBe(true);
+ expect(results.utilsFunctionWorks).toBe(true);
+
+ // Verify side effects and empty modules
+ expect(results.sideEffectRan).toBe(true);
+ expect(results.emptyModuleHandled).toBe(true);
+ });
+
+});
\ No newline at end of file
diff --git a/packages/gunzip-scripts/tests/test-utils.ts b/packages/gunzip-scripts/tests/test-utils.ts
new file mode 100644
index 0000000..f9987e9
--- /dev/null
+++ b/packages/gunzip-scripts/tests/test-utils.ts
@@ -0,0 +1,73 @@
+import { gzipSync } from 'fflate';
+import { writeFileSync, mkdirSync } from 'fs';
+import { join } from 'path';
+
+export interface TestScript {
+ content: string;
+ type: 'umd' | 'esm';
+ path?: string;
+ name?: string;
+}
+
+export function createGzippedDataUri(content: string): string {
+ const buffer = new TextEncoder().encode(content);
+ const gzipped = gzipSync(buffer);
+ const base64 = Buffer.from(gzipped).toString('base64');
+ return `data:application/gzip;base64,${base64}`;
+}
+
+export function generateTestHtml(
+ scripts: TestScript[],
+ options: {
+ title?: string;
+ gunzipVersion?: 'default' | 'esm';
+ additionalHead?: string;
+ additionalBody?: string;
+ } = {}
+): string {
+ const {
+ title = 'Test gunzipScripts',
+ gunzipVersion = 'esm',
+ additionalHead = '',
+ additionalBody = ''
+ } = options;
+
+ const scriptTags = scripts.map(script => {
+ const dataUri = createGzippedDataUri(script.content);
+
+ if (script.type === 'umd') {
+ return ``;
+ } else {
+ const pathAttr = script.path ? `data-path="${script.path}"` : '';
+ const nameAttr = script.name ? `data-name="${script.name}"` : '';
+ const attrs = [pathAttr, nameAttr].filter(Boolean).join(' ');
+ return ``;
+ }
+ }).join('\n ');
+
+ return `
+
+
+