gaoluyang
2026-06-24 c0cb161bb52ce0fbdce5c66ec391d107c75e2452
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import { beforeEach, describe, expect, it, vi } from 'vitest';
 
import { loadScript } from '../resources';
 
describe('loadScript', () => {
  beforeEach(() => {
    // 每个测试前清空 head,保证环境干净
    document.head.innerHTML = '';
  });
 
  it('should resolve when the script loads successfully', async () => {
    // happy-dom v20+ auto-fires 'load' via handleDisabledFileLoadingAsSuccess
    const promise = loadScript('/test-script.js');
 
    const script = document.querySelector(
      'script[src="/test-script.js"]',
    ) as HTMLScriptElement;
    expect(script).toBeTruthy();
 
    await expect(promise).resolves.toBeUndefined();
  });
 
  it('should not insert duplicate script and resolve immediately if already loaded', async () => {
    // 先手动插入一个相同 src 的 script
    const existing = document.createElement('script');
    existing.src = 'bar.js';
    document.head.append(existing);
 
    // 再次调用
    const promise = loadScript('bar.js');
 
    // 立即 resolve
    await expect(promise).resolves.toBeUndefined();
 
    // head 中只保留一个
    const scripts = document.head.querySelectorAll('script[src="bar.js"]');
    expect(scripts).toHaveLength(1);
  });
 
  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');
 
    appendSpy.mockRestore();
 
    expect(capturedScript).toBeTruthy();
    if (!capturedScript) {
      throw new Error('Expected the captured script element to exist');
    }
    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('/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="/test-script.js"]',
    );
    expect(scripts).toHaveLength(1);
  });
});