feat: migrate to Tailwind CSS v4 (#7614)

* chore: update deps

* feat: use jsonc/x language

* chore: update eslint 10.0

* fix: no-useless-assignment

* feat: add CLAUDE.md

* chore: ignore

* feat: claude

* fix: lint

* chore: suppot eslint v10

* fix: lint

* fix: lint

* fix: type check

* fix: unit test

* fix: Suggested fix

* fix: unit test

* chore: update stylelint v17

* chore: update all major deps

* fix:  echarts console warn

* chore: update vitest v4

* feat: add skills ignores

* chore: update deps

* chore: update deps

* fix: cspell

* chore: update deps

* chore: update tailwindcss v4

* chore: remove postcss config

* fix: no use catalog

* chore: tailwind v4 config

* fix: tailwindcss v4 sort

* feat: use eslint-plugin-better-tailwindcss

* fix: Interference between enforce-consistent-line-wrapping, jsx-curly-brace-presence and Prettier

* fix: Interference between enforce-consistent-line-wrapping, jsx-curly-brace-presence and Prettier

* fix(lint): resolve prettier and better-tailwindcss formatting conflicts

* fix(tailwind): update theme references and lint sources

* style(format): normalize apps docs and playground vue files

* style(format): normalize core ui-kit components

* style(format): normalize effects ui and layout components
This commit is contained in:
xingyu
2026-03-10 05:08:45 +08:00
committed by GitHub
parent aa7d8630b5
commit a4736a49f8
289 changed files with 5286 additions and 6331 deletions

View File

@@ -1,10 +1,7 @@
import { beforeEach, describe, expect, it } from 'vitest';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { loadScript } from '../resources';
const testJsPath =
'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js';
describe('loadScript', () => {
beforeEach(() => {
// 每个测试前清空 head保证环境干净
@@ -12,18 +9,14 @@ describe('loadScript', () => {
});
it('should resolve when the script loads successfully', async () => {
const promise = loadScript(testJsPath);
// happy-dom v20+ auto-fires 'load' via handleDisabledFileLoadingAsSuccess
const promise = loadScript('/test-script.js');
// 此时脚本元素已被创建并插入
const script = document.querySelector(
`script[src="${testJsPath}"]`,
'script[src="/test-script.js"]',
) as HTMLScriptElement;
expect(script).toBeTruthy();
// 模拟加载成功
script.dispatchEvent(new Event('load'));
// 等待 promise resolve
await expect(promise).resolves.toBeUndefined();
});
@@ -45,37 +38,42 @@ describe('loadScript', () => {
});
it('should reject when the script fails to load', async () => {
let capturedScript: HTMLScriptElement | null = null;
// 拦截 append捕获 script 元素但不插入 DOM
// 防止 happy-dom v20+ 自动触发 load 事件
const appendSpy = vi
.spyOn(document.head, 'append')
.mockImplementation((...nodes) => {
for (const node of nodes) {
if (node instanceof HTMLScriptElement) {
capturedScript = node;
}
}
});
const promise = loadScript('error.js');
const script = document.querySelector(
'script[src="error.js"]',
) as HTMLScriptElement;
expect(script).toBeTruthy();
appendSpy.mockRestore();
// 模拟加载失败
script.dispatchEvent(new Event('error'));
expect(capturedScript).toBeTruthy();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
capturedScript!.dispatchEvent(new Event('error'));
await expect(promise).rejects.toThrow('Failed to load script: error.js');
});
it('should handle multiple concurrent calls and only insert one script tag', async () => {
const p1 = loadScript(testJsPath);
const p2 = loadScript(testJsPath);
const script = document.querySelector(
`script[src="${testJsPath}"]`,
) as HTMLScriptElement;
expect(script).toBeTruthy();
// 触发一次 load两个 promise 都应该 resolve
script.dispatchEvent(new Event('load'));
const p1 = loadScript('/test-script.js');
const p2 = loadScript('/test-script.js');
// happy-dom v20+ auto-fires 'load',两个 promise 都应该 resolve
await expect(p1).resolves.toBeUndefined();
await expect(p2).resolves.toBeUndefined();
// 只插入一次
const scripts = document.head.querySelectorAll(
`script[src="${testJsPath}"]`,
'script[src="/test-script.js"]',
);
expect(scripts).toHaveLength(1);
});