fix: Add babel configuration for Playwright to handle TypeScript declare fields

- Configure babel plugins for TypeScript with allowDeclareFields option
- Add module resolver for @ alias to src directory
- Create custom babel plugin to stub Vue/CSS imports
- Add browser globals polyfill using happy-dom for Node.js context
- Update playwright.i18n.config.ts with babel configuration

This enables collect-i18n tests to run with proper TypeScript and module transformations.
This commit is contained in:
snomiao
2025-09-12 08:16:37 +00:00
parent 4ec6223189
commit 540b6f3d26
8 changed files with 1475 additions and 374 deletions

18
babel-plugin-stub-vue.js Normal file
View File

@@ -0,0 +1,18 @@
module.exports = function() {
return {
visitor: {
ImportDeclaration(path) {
const source = path.node.source.value;
if (source.endsWith('.vue')) {
// Replace Vue component imports with a stub
const specifiers = path.node.specifiers;
if (specifiers.length > 0) {
const name = specifiers[0].local.name;
// Create a simple stub object
path.replaceWithSourceString(`const ${name} = {};`);
}
}
}
}
};
};

24
babel.config.json Normal file
View File

@@ -0,0 +1,24 @@
{
"presets": [
"@babel/preset-env",
[
"@babel/preset-typescript",
{
"allowDeclareFields": true,
"onlyRemoveTypeImports": true
}
]
],
"plugins": [
[
"babel-plugin-module-resolver",
{
"root": ["./"],
"alias": {
"@": "./src"
}
}
],
"@vue/babel-plugin-jsx"
]
}

View File

@@ -32,12 +32,17 @@
"knip": "knip --cache",
"knip:no-cache": "knip",
"locale": "lobe-i18n locale",
"collect-i18n": "npx playwright test --config=playwright.i18n.config.ts",
"collect-i18n": "playwright test --config=playwright.i18n.config.ts",
"json-schema": "tsx scripts/generate-json-schema.ts",
"storybook": "nx storybook -p 6006",
"build-storybook": "storybook build"
},
"devDependencies": {
"@babel/core": "^7.28.4",
"@babel/plugin-transform-modules-commonjs": "^7.27.1",
"@babel/plugin-transform-typescript": "^7.28.0",
"@babel/preset-env": "^7.28.3",
"@babel/preset-typescript": "^7.27.1",
"@eslint/js": "^9.8.0",
"@iconify-json/lucide": "^1.2.66",
"@iconify/tailwind": "^1.2.0",
@@ -62,7 +67,15 @@
"@vitejs/plugin-vue": "^5.1.4",
"@vitest/coverage-v8": "^3.2.4",
"@vitest/ui": "^3.0.0",
"@vue/babel-plugin-jsx": "^1.5.0",
"@vue/test-utils": "^2.4.6",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-plugin-module-resolver": "^5.0.2",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-import-ignore": "^1.1.0",
"babel-plugin-transform-vue-jsx": "^3.7.0",
"babel-preset-env": "^1.7.0",
"babel-preset-typescript-vue3": "^2.1.1",
"eslint": "^9.34.0",
"eslint-config-prettier": "^10.1.2",
"eslint-plugin-prettier": "^5.2.6",

View File

@@ -1,6 +1,6 @@
import { defineConfig } from '@playwright/test'
export default defineConfig({
const config: any = defineConfig({
testDir: './scripts',
use: {
baseURL: 'http://localhost:5173',
@@ -8,5 +8,40 @@ export default defineConfig({
},
reporter: 'list',
timeout: 60000,
testMatch: /collect-i18n-.*\.ts/
testMatch: /collect-i18n-.*\.ts/,
// Start dev server before running tests
webServer: {
command: 'pnpm dev',
url: 'http://localhost:5173',
reuseExistingServer: true,
timeout: 60000
}
})
// Configure babel plugins for TypeScript with declare fields and module resolution
config['@playwright/test'] = {
babelPlugins: [
// Stub Vue and CSS imports first to prevent parsing errors
['babel-plugin-stub-vue-imports'],
// Module resolver to handle @ alias
[
'babel-plugin-module-resolver',
{
root: ['./'],
alias: {
'@': './src'
}
}
],
// Then TypeScript transformation with declare field support
[
'@babel/plugin-transform-typescript',
{
allowDeclareFields: true,
onlyRemoveTypeImports: true
}
]
]
}
export default config

1686
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
import './setup-browser-globals.js'
import * as fs from 'fs'
import { comfyPageFixture as test } from '../browser_tests/fixtures/ComfyPage'

View File

@@ -1,3 +1,4 @@
import './setup-browser-globals.js'
import * as fs from 'fs'
import { comfyPageFixture as test } from '../browser_tests/fixtures/ComfyPage'

View File

@@ -0,0 +1,65 @@
// Polyfill browser globals for Node.js context during test imports
import { Window } from 'happy-dom';
// Define build-time constants
if (typeof globalThis.__USE_PROD_CONFIG__ === 'undefined') {
globalThis.__USE_PROD_CONFIG__ = false;
}
// Create a happy-dom window instance
const window = new Window({
url: 'http://localhost:5173/',
width: 1024,
height: 768
});
// Expose DOM globals (only set if not already defined)
if (!globalThis.window) globalThis.window = window;
if (!globalThis.document) globalThis.document = window.document;
if (!globalThis.location) globalThis.location = window.location;
if (!globalThis.navigator) {
try {
globalThis.navigator = window.navigator;
} catch (e) {
// navigator might be read-only in some environments
}
}
if (!globalThis.HTMLElement) globalThis.HTMLElement = window.HTMLElement;
if (!globalThis.Element) globalThis.Element = window.Element;
if (!globalThis.Node) globalThis.Node = window.Node;
if (!globalThis.NodeList) globalThis.NodeList = window.NodeList;
if (!globalThis.DOMParser) globalThis.DOMParser = window.DOMParser;
if (!globalThis.XMLSerializer) globalThis.XMLSerializer = window.XMLSerializer;
if (!globalThis.localStorage) globalThis.localStorage = window.localStorage;
if (!globalThis.sessionStorage) globalThis.sessionStorage = window.sessionStorage;
if (!globalThis.CustomEvent) globalThis.CustomEvent = window.CustomEvent;
if (!globalThis.Event) globalThis.Event = window.Event;
if (!globalThis.MouseEvent) globalThis.MouseEvent = window.MouseEvent;
if (!globalThis.KeyboardEvent) globalThis.KeyboardEvent = window.KeyboardEvent;
if (!globalThis.getComputedStyle) globalThis.getComputedStyle = window.getComputedStyle;
if (!globalThis.requestAnimationFrame) globalThis.requestAnimationFrame = window.requestAnimationFrame;
if (!globalThis.cancelAnimationFrame) globalThis.cancelAnimationFrame = window.cancelAnimationFrame;
// Add ResizeObserver polyfill
if (!globalThis.ResizeObserver) {
globalThis.ResizeObserver = class ResizeObserver {
constructor(callback) {
this.callback = callback;
}
observe() {}
unobserve() {}
disconnect() {}
};
}
// Add IntersectionObserver polyfill
if (!globalThis.IntersectionObserver) {
globalThis.IntersectionObserver = class IntersectionObserver {
constructor(callback) {
this.callback = callback;
}
observe() {}
unobserve() {}
disconnect() {}
};
}