You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Web单元测试中window.open()返回null的问题排查

解决Flutter Web单元测试中window.open返回null的问题

我明白你遇到的困扰——代码在真实浏览器里工作正常,但单元测试里因为window.open返回null而失败。这其实是测试环境和真实浏览器环境的差异导致的:测试用的Chrome实例会默认阻止弹窗,并且不会返回真实的窗口对象,所以open方法返回null,但这并不代表你的代码逻辑有问题。

下面是具体的解决方案,帮你调整测试逻辑,让测试能正确验证功能:

1. 重构代码,方便依赖注入

首先,我们可以稍微修改PrintReports的launchURL方法,让它可以接受一个可选的Window参数,这样测试时我们可以传入模拟对象,而不是直接依赖全局的html.window:

import 'package:flutter_web/material.dart';
import 'dart:html' as html;

// ... 其他代码不变

class PrintReports extends StatelessWidget {
  const PrintReports({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        RaisedButton(
          child: const Text("Print A Form . . ."),
          color: Colors.blue,
          onPressed: () => {
            // 这里调用时可以不传window参数,默认用全局的html.window
            launchURL("your-real-url-here"),
          },
        ),
      ],
    );
  }

  // 添加可选的window参数,用于测试注入mock
  Future<void> launchURL(String download_url, {html.Window? window}) async {
    try {
      // 使用传入的window或者全局的html.window
      final targetWindow = window ?? html.window;
      targetWindow.open(download_url, "Get_Submission");
    } catch (e) {
      print(e);
    }
  }
}

2. 使用Mock模拟Window对象,验证调用行为

我们不需要测试浏览器的window.open本身(那是浏览器的功能),我们需要测试的是我们的代码是否正确调用了window.open,并且传入了正确的参数。这里可以用mockito包来模拟Window对象:

第一步:添加依赖

在pubspec.yaml的dev_dependencies里添加mockito:

dev_dependencies:
  test: any
  mockito: ^5.4.0 # 用最新版本即可

第二步:编写测试代码

import 'dart:html' as html;
import 'package:flutter_tests/main.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';

// 创建Mock类模拟html.Window
class MockWindow extends Mock implements html.Window {}

void main(){
  test("launchURL calls window.open with correct URL and window name", () async {
    // Arrange:准备测试环境和mock对象
    final mockWindow = MockWindow();
    final printReports = PrintReports();
    const testUrl = "https://someurl.com/download";
    const expectedWindowName = "Get_Submission";

    // Act:调用要测试的方法
    await printReports.launchURL(testUrl, window: mockWindow);

    // Assert:验证mock对象的open方法是否被正确调用
    verify(mockWindow.open(testUrl, expectedWindowName)).called(1);
  });
}

为什么原来的测试会失败?

在测试用的Chrome实例中,浏览器会自动阻止弹窗,并且不会返回真实的WindowBase对象,所以window.open返回null。但这是测试环境的限制,不是你的代码问题——真实用户使用时,只要允许弹窗,这个方法就能正常工作。

我们的测试思路应该从验证返回值转换为验证行为是否正确:确认我们的代码确实调用了window.open,并且传入了正确的URL和窗口名称,这就足够证明功能逻辑是正确的。

运行修改后的测试,应该就能顺利通过了!

内容的提问来源于stack exchange,提问作者skillit zimberg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:01:23