十、测试和调试 JavaScript

在每个软件生命周期中,测试和调试都扮演着重要的角色。彻底的测试使软件完美无瑕,良好的调试技术不仅使故障排除变得容易,而且有助于通过深入到准确的点来识别和修复任何问题。

测试是创建任何健壮应用的核心要素。然而,应用使用不同的实践和框架来服务特定的目标,并且架构根据应用的性质而有所不同。因此,有时开发人员很难测试客户端代码,例如,如果应用在页面本身包含一些 JavaScript 代码,例如内联事件处理程序,则使其与页面紧密耦合。另一方面,即使将 JavaScript 代码模块化到不同的模块中,也会带来一些测试套件的限制,使得执行应用的测试过程变得更加困难。

调试是在应用中查找和修复错误的过程。它是软件开发中最重要和最核心的技能之一。如果开发人员牢牢掌握了调试工具并了解调试的细节,他们可以快速确定根本原因并开始修复错误。调试是任何软件开发生命周期中的一个基本过程。无论是一个复杂的应用还是一个简单的应用,跟踪和纠正错误调试都起着重要的作用。它帮助开发人员通过断点中断程序执行,并通过进入程序执行链来识别程序流。此外,几乎所有调试工具都提供了其他有用的信息,例如监视程序中使用的变量或对象的当前状态,以及在调试生命周期的每个阶段监视它们。

测试 JavaScript 代码

通常,web 应用会经历不同类型的测试,例如用户界面UI)测试,它通过向表单输入来检查 UI 的功能,并验证应用的行为。这种类型的测试主要是手动或通过自动测试工具完成的。另一种类型的测试是负载测试,它主要用于检查应用的性能,并在应用上施加一些负载。简单地说,它可以是一个登录到具有多个用户的应用的示例,或者通过自动化例程执行一些操作来测试应用的行为。还有一些测试类型,但是确保应用功能并证明应用是否符合要求的最基本的测试类型是单元测试。在本节中,我们将讨论如何使用 Jasmine(一种流行的 JavaScript 单元测试框架)对 JavaScript 代码进行单元测试,并将其与 Karma 和 Grunt 一起使用 Visual Studio 2015 IDE 在 ASP.NET 应用中执行测试用例。

单元测试

单元测试是一种方法,用于测试模块的各个单元以及相关数据和程序,以验证应用的功能是否符合要求。单元测试由开发人员完成,它允许开发人员测试应用的每个用例,以确保它满足需求并按预期工作。

单元测试的基本优势在于,它将应用的每个部分分割成一个较小的单元,并帮助开发人员在开发周期中首先关注并识别 bug。单元测试是任何应用经受的第一次测试,允许测试人员和开发人员发布应用进行用户验收测试UAT)。

编写单元测试

要测试 JavaScript 代码,有许多测试套件可用。最受欢迎的是茉莉花、摩卡和奎特。在这一章中,我们将使用茉莉花与因果报应和咕噜。

茉莉花

Jasmine 是一个行为驱动的开发框架,用于测试 JavaScript 代码。这提供了某些函数,如it()describe()expect()等,用于为 JavaScript 代码编写测试脚本。这个框架的基本优点是,它非常容易理解,并且有助于用非常简单的代码行编写测试 JavaScript 代码。

例如,考虑下面的 JavaScript 代码,将两个数字传递为参数:

(function () {
  var addTwoNumbers = function (x, y) {
    return x+y;
  };

})();

前面的功能的测试用例将类似于下面的:

describe('Calculator', function () {
  it('Results will be 20 for 10 + 10', function () {
    expect(addTwoNumbers(10,10)).toBe(20);
  });
});

业力

Karma 是 JavaScript 的测试运行程序,可以与其他测试框架(如 Jasmine、Mocha 等)集成。它通过提供模拟测试环境和加载浏览器来执行通过 Jasmine 或其他测试框架定义的测试用例,这些浏览器根据配置执行测试 JavaScript 代码。Karma 配置文件称为Karma.config.js。执行测试后,结果将显示在控制台窗口中。

咕哝

咕噜声相当于咕噜声。用于执行 CSS 文件或 JavaScript 文件的缩小、多个 JavaScript 文件的串联和合并等任务。Grunt 有数百个插件可用于自动化特定任务。与前面使用 Gulp 的章节不同,我们将使用 Grunt,看看它为 Karma(测试运行者)和 Jasmine(测试套件)提供了什么。Grunt 和 Gulp 都是著名的开发任务执行者。在这里使用 Grunt 的原因是为了了解另一个 JavaScript 任务运行程序,它同样受到 Visual Studio 2015 的知名度和支持,并讨论它提供的用于使用 Karma 和 Jasmine 执行测试的包。

使用 Jasmine、Karma 和 Grunt 开发单元测试

在本节中,我们将开发一个简单的单元测试,展示如何使用 Jasmine、Karma 和 Grunt 框架在 ASP.NET 核心应用中进行单元测试。首先,从 Visual Studio 2015 创建一个 ASP.NET 核心应用。

添加包

在 ASP.NET 核心应用中打开文件package.json,添加gruntgrunt-karmakarmakarma-phantomjs-launcherkarma-jasminekarma-spec-reporterkarma-cli等包,如下图:

Adding packages

下表显示了每个包的说明:

|

包名

|

描述

| | --- | --- | | grunt | 这将配置和运行任务 | | grunt-karma | 这是 Karma test runner 的 Grunt 插件 | | karma | 这是 JavaScript 的测试运行程序 | | karma-phantomjs-launcher | 这是启动 PhantomJS 浏览器的 Karma 插件 | | karma-jasmine | 这是 Jasmine 测试套件的 Karma 插件 | | karma-spec-reporter | 这是 Karma 插件,用于向控制台报告测试结果 | | karma-cli | 这是 Karma 命令行界面 |

添加 Grunt 文件

在 ASP.NET 应用中添加Gruntfile.js以定义 Grunt 任务。Gruntfile.js是配置所有任务的主文件。已配置的任务可以在 Visual Studio 中的任务运行器资源管理器窗口中看到。

增加卡玛规范

Gruntfile.js文件提供加载 Grunt 时调用的主initConfig()方法。这是我们定义业力规范的起点。

以下是initConfig()方法中定义的 Karma 规范:

grunt.initConfig({
  karma: {
    unit: {
      options: {
        frameworks: ['jasmine'],
        singleRun: true,
        browsers: ['PhantomJS'],
        files: [
          './wwwroot/js/**/*.js',
          './wwwroot/tests/**/*.test.js'

        ]
      }
    }
  }
});

在前面的脚本中,我们首先指定 Karma 的目标平台。在karma中,我们将指定用于运行单元测试的单元。在unit中,我们可以定义某些配置属性,如frameworkssingleRunbrowsersfiles

  • frameworks: This is an array of test frameworks that we want to use. In this exercise, we used Jasmine. However, other frameworks such as Mocha and QUnit can also be used.

    提示

    请注意,当使用 Karma 中的任何框架时,必须使用节点包管理器NPM单独安装该框架的额外插件/库。

  • singleRun:如果将此设置为true,Karma 将开始捕获已配置的浏览器并对其执行测试。一旦测试完成,它就会顺利退出。

  • browsers:这是一个数组,用逗号分隔的值定义多个浏览器。我们在示例中使用了 PhantomJS,它是一个无头浏览器,在后台运行测试。Karma 支持其他浏览器,如 Chrome、Firefox、IE 和 Safari,可以通过此属性进行配置。
  • files:此包含所有测试文件、源文件和依赖项。例如,如果我们在测试脚本或原始源代码中使用 jQuery,那么我们也可以将路径添加到此库。在前面的配置中,我们使用通配符加载js文件夹下定义的所有源文件,并使用test.js后缀测试tests文件夹下的文件。

业力配置中还有很多属性可以使用,这里可以参考:

http://karma-runner.github.io/0.13/config/configuration-file.html

加载 npm 任务

要加载 Karma test runner 工具,需要在 Karma 配置后的Gruntfile.js中指定,如下所示:

grunt.loadNpmTasks('grunt-karma');
注册任务

最后,我们将添加 Grunt 任务来注册任务。第一个参数是任务名称,它将在 Visual Studio 中的任务运行器资源管理器中可用,第二个参数使用数组执行多个任务:

grunt.registerTask('test', ['karma']);

源 JavaScript 文件

在这个示例中,我们有一个product.js文件,其中包含一个saveProduct()方法,该方法将在保存按钮的点击事件中调用。

将此文件添加到wwwroot/js文件夹路径:

window.product = window.product || {};

(function () {
  var saveProduct = function () {
    var prodCode = document.getElementById('txtProdCode').value;
    var prodUnitPrice = document.getElementById('txtProdUnitPrice').value;
    var prodExpiry = document.getElementById('txtProdExpiry').value;
    var prodQuantity = document.getElementById('txtProdQuantity').value;
    var totalPrice = prodUnitPrice * prodQuantity;
    document.getElementById('totalAmount').innerHTML = totalPrice;
  };

  window.product.init = function () {
    document.getElementById('save').addEventListener('click', saveProduct);
  };

})();

在前面的代码片段中,我们有一个saveProduct()方法,该方法读取 HTML 元素并根据输入的数量和单价计算总价。在页面初始化中,我们将注册保存按钮的click事件处理程序,调用saveProduct()方法并计算总价。

提示

建议将 JavaScript 代码与 HTML 标记分开。

增加单元测试脚本文件

在这里,我们将在wwwroot/tests文件夹下添加另一个 JavaScript 文件,并将其命名为product.test.js。编写测试时,您可以添加*.test.js后缀以使其唯一标识,并将其与源 JavaScript 文件分离。

以下是product.test.js的代码:

describe('Product', function () {

  // inject the HTML fixture for the tests
  beforeEach(function () {
    var fixture = '<div id="fixture">'+
      '<input id="txtProdCode" type="text">' +
      '<input id="txtProdExpiry" type="text">' +
      '<input id="txtProdUnitPrice" type="text">' +
      '<input id="txtProdQuantity" type="text">' +
      '<input id="save" type="button" value="Save">' +
      'Total Amount: <span id="totalAmount" /></div>';

    document.body.insertAdjacentHTML(
      'afterbegin',
      fixture);
  });

  // remove the html fixture from the DOM
  afterEach(function () {
    document.body.removeChild(document.getElementById('fixture'));
  });

  // call the init function of calculator to register DOM elements
  beforeEach(function () {
    window.product.init();
  });

  it('Expected result should be 0 if the Unit price is not valid', function () {
    document.getElementById('txtProdUnitPrice').value = 'a';
    document.getElementById('txtProdQuantity').value = 2;
    document.getElementById('save').click();
    expect(document.getElementById('totalAmount').innerHTML).toBe('0');
  });

  it('Expected result should be 0 if the Product Quantity is not valid', function () {
    document.getElementById('txtProdUnitPrice').value = 30;
    document.getElementById('txtProdQuantity').value = 'zero';
    document.getElementById('save').click();
    expect(document.getElementById('totalAmount').innerHTML).toBe('0');
  });

});

Jasmine 框架提供了某些关键字来定义在特定条件下运行的特定块,如下所示:

  • describe():这是一个全局 Jasmine 函数,包含两个参数:字符串和函数。字符串是要测试的功能的名称。该函数包含实际实现 Jasmine 套件的代码,并包含单元测试的逻辑。
  • it():这里通过调用全局 Jasmine 函数it()来定义规范。这也需要字符串和函数,其中包含实际的单元测试名称,函数块包含要执行的代码的实际逻辑以及预期结果。
  • expect():可以使用expect()函数指定预期结果,该函数取it()函数中定义的某个值。这还与匹配器函数(如toBe()not.toBe())链接,以匹配或取消匹配预期值。

在.NET 中,相当于排列动作断言模式。这里,Arrange 用于初始化对象并设置传递给被测试方法的数据值。Act 模式实际上调用了被测试的方法,并且 Assert 验证了被测试的方法的行为是否符合预期。

运行测试任务

运行这些任务非常简单,只需通过 Visual Studio 2015 中的任务运行器资源管理器窗口运行即可。以下是显示在Gruntfile.js中定义的任务的任务运行器资源管理器窗口的屏幕截图:

Running test task

当我们运行测试任务时,它将显示类似于以下输出的内容:

Running test task

在我们的product.test.js测试脚本中,我们有两个任务。一个是检查将字符串值传递给两个元素中的一个,例如txtProdUnitPricetxtProdQuantity是否会返回0。由于我们的product.js 文件没有处理这种情况,它将给出一个错误。

为了解决这个问题,我们将修改我们的product.js并添加这两行来处理该逻辑,以检查该值是否为数字:

prodUnitPrice = isNaN(prodUnitPrice) ? 0 : prodUnitPrice;
prodQuantity = isNaN(prodQuantity) ? 0 : prodQuantity;

现在,当我们再次运行测试时,我们将获得以下输出:

Running test task

在前面的示例中,我们在product.test.js文件的beforeEach()函数中定义了 HTML 标记。对于简单的应用,将 HTML 标记重新定义为 fixture 并使用它们执行测试可能不是一个麻烦的过程。但是,大多数 web 应用都使用一些客户端框架,如 Knockout、AngularJS 等,这些框架将 HTML 视图中指定的控件绑定分离到 ViewModel,而此 ViewModel 负责读取或写入控件值。

在下面的示例中,我们将使用实现模型-视图-模型模式的 Knockout JavaScript 库,并了解如何以这种方式编写单元测试。

使用淘汰和运行测试实现模型-视图-模型

模型视图视图模型MVVM是一种用于构建用户界面的设计模式。将分为三部分,如下图所示:

Implementing Model-View-ViewModel using Knockout and Run test

这三个部分描述为:

  • 模型:包含后端逻辑,通过与持久存储通信来调用后端服务并保存或停用数据。
  • 视图模型:包含视图特定的操作和数据。它表示视图元素绑定到的视图的模型。例如,包含一些 HTML 元素的表单将有一个 ViewModel,它是一个包含一些属性的对象,用于将这些控件和数据绑定在一起。
  • 视图:这是用户交互的用户界面。它显示来自 ViewModel 的信息,在 ViewModel 上引发事件,并在 ViewModel 更改时进行更新。

让我们通过以下步骤使用淘汰JavaScript 库实现 MVVM 模式。

添加淘汰包

首先,让我们通过bower.json在 ASP.NET 核心应用中添加 Knockout.js。可以通过在bower.json文件的“依赖项”部分创建条目来添加该包,Visual Studio 会自动下载该包并将其放置在wwwroot/lib/knockout文件夹中。

bower.json文件中可以添加以下语句:

"knockout": "3.4.0",

新增 ProductViewModel

ProductViewModel包含产品代码、单价、数量、有效期和总金额等属性。以下是ProductViewModel.js的代码片段:

var ProductViewModel = function () {

  this.prodCode = ko.observable('');
  this.prodUnitPrice = ko.observable(0);
  this.prodQuantity = ko.observable(0);
  this.prodExpiry = ko.observable('');
  this.prodTotalAmount =0;

  ko.applyBindings(this);

  this.saveProduct=function(){
    var unitPrice = this.prodUnitPrice();
    var quantity = this.prodQuantity();
    var total = unitPrice * quantity;
    this.prodTotalAmount = total;

    //call some service to save product
  }

};

在前面的代码片段中,我们有一个ProductViewModel类,它包含几个属性,每个属性都被分配给ko.observable()

ko基本上是一个敲除对象,它提供了一种将对象模型链接到视图的补充方式,其中ko.observable()是一个敲除函数,它使模型属性可见并与视图数据同步。这意味着当 ViewModel 属性的值更改时,视图将更新;修改控件值时,ViewModel 属性将更新。

值也是预先填充的,如下面的代码段所示。在以下语句中传递0将在控件绑定完成时设置控件值0

this.prodUnitPrice = ko.observable(0)

ko.applyBindings()实际激活 Knockout 以执行模型属性与视图元素的绑定。

添加产品视图

Knockout 提供了一种将 ViewModel 属性绑定到控件元素的非常好的方法。绑定由两个项组成,名称和值,用冒号分隔。要将 ViewModel 与输入元素绑定,我们可以使用 data bind 属性并指定值名称,后跟:和 ViewModel 的属性名称。每个控件都有一组特定的属性,可用于相应地绑定元素。

例如,span元素可以使用文本名称绑定到视图模型属性,如下所示:

Product code is: <span data-bind="text: prodCode"></span>

以下是产品视图的修改版本:

<body>
  <div>
    <label> Product Code: </label>
    <input type="text" data-bind="value: prodCode" />
  </div>
  <div>
    <label> Product Unit Price: </label>
    <input type="text" data-bind="value: prodUnitPrice" />
  </div>
  <div>
    <label> Product Expiry: </label>
    <input type="text" data-bind="value: prodExpiry" />
  </div>
  <div>
    <label> Product Quantity: </label>
    <input type="text" data-bind="value: prodQuantity" />
  </div>
  <div>
    <input id="btnSaveProduct" type="button" value="Save Product" />
  </div>
  <script src="lib/knockout/dist/knockout.js"></script>
  <script src="Js/ProductViewModel.js"></script>
  <script>
    (function () {
      var prod = new ProductViewModel();
      document.getElementById("btnSaveProduct").onclick = function () { prod.saveProduct(); };
    })();
  </script>
</body>

这就是我们在产品视图中配置淘汰所需的全部内容。点击btnSaveProduct按钮,计算总金额并调用产品服务保存记录。

修改测试配置

以下是之前创建的修改版本Gruntfile.js。我们在files数组中添加了ProductViewModel.js和敲除依赖项:

/*
This file in the main entry point for defining grunt tasks and using grunt plugins.
*/
module.exports = function (grunt) {
  grunt.initConfig({
    karma: {
      unit: {
        options: {
          frameworks: ['jasmine'],
          singleRun: true,
          browsers: ['PhantomJS'],
          files: [
            './wwwroot/lib/knockout/dist/knockout.js',
            './wwwroot/js/ProductViewModel.js',
            './wwwroot/test/**/product.test.js'
          ]
        }
      }
    }
  });

  grunt.loadNpmTasks('grunt-karma');
  grunt.registerTask('test', ['karma']);
};

修改产品测试脚本

由于我们不直接依赖 HTML 视图,我们可以通过产品视图模型测试我们的单元测试用例。以下是未定义任何固定装置的product.test.js修改版本:

describe('Product', function () {

  it('Expected Total Amount should be 600', function () {
    var product = new ProductViewModel();
    product.prodQuantity(3);
    product.prodUnitPrice(200);
    product.saveProduct();
    expect(product.prodTotalAmount).toBe(600);
  });
});

测试运行时会产生以下输出:

Modifying the product-testing script

调试 JavaScript

JavaScript 在客户端浏览器上运行,几乎所有浏览器,如 Internet Explorer、Microsoft Edge、Chrome 和 Firefox,都提供集成的 JavaScript 调试器和开发工具窗口。使用 VisualStudio,我们还可以通过将 Internet Explorer 设置为默认浏览器来调试 JavaScript 代码。Chrome 不支持开箱即用,但通过某些步骤,它可以实现。

Visual Studio 2015 中的调试选项

VisualStudio 提供了一些不错的功能来调试 JavaScript 并排除错误。Visual Studio 中的 JavaScript 调试仅适用于 Internet Explorer。可以通过在调试模式下启动应用,然后在 JavaScript 代码中放置一些断点来启动调试。当遇到断点时,我们可以在 VisualStudio 中使用我们已经知道并用于调试 C#和 VB.NET 代码的各种调试选项。诸如单步执行(F11)、单步执行(F10)、单步执行(Shift+F11)、条件断点和手表等选项都可以使用 JavaScript 代码。

使用 Internet Explorer 从 Visual Studio 进行调试

对于特定的 web 应用项目,Visual Studio 中的默认浏览器可以通过web 浏览器(Internet Explorer)Internet Explorer选项进行设置,如下图所示:

Debugging from Visual Studio with Internet Explorer

使用 Google Chrome 从 Visual Studio 进行调试

Visual Studio 2015 不为调试 JavaScript 应用提供开箱即用支持,但使用 Internet Explorer 除外。或者,使用 Node.js,在 Visual Studio 中调试工作非常好,从技术上讲,Node.js 和 Google Chrome 都基于 V8 引擎,没有缺点。

要在 Visual Studio 中开始使用 Chrome 进行调试,我们必须使用远程调试器参数运行 Googlechrome.exe文件。以下命令通过远程调试运行 Google Chrome,并且从 Visual Studio 中,可以通过指向同一 Chrome 实例来附加该命令:

chrome.exe – remote-debugging-port=9222

9222是 Visual Studio 在连接到其进程时连接的默认端口。

在 VisualStudio 中,您可以通过点击菜单栏中的Ctrl+Alt+P来附加进程,或者通过进入调试附加到进程并选择 Chrome 实例来附加进程。

开发工具

几乎所有的浏览器都支持内置开发工具,帮助调试和排除 JavaScript 错误。这些工具通常被称为F12 工具,通过点击F12键打开开发者工具窗口。

Microsoft Edge 中的调试选项

Microsoft Edge 是最轻量级的 web 浏览器之一,布局引擎围绕 web 标准构建。它包含一些新功能,如 Cortana、注释工具和阅读模式,使其在其他浏览器中具有优势。

Microsoft Edge 中的开发者工具窗口与下图类似:

Debugging options in Microsoft Edge

左上角的第一个窗格是显示包含页面的 JavaScript 内容的脚本窗格。

右上角的第二个窗格是一个手表窗格,其中显示变量值。

左下角的第三个窗格是显示消息的控制台窗口,所有消息都使用console.log()记录;呼叫打印在控制台窗口上。Microsoft Edge 在三个不同的选项卡中提供错误、警告和消息,让您可以大致了解错误、警告和消息,它还可以帮助开发人员通过单击错误行链接直接跳转到确切的代码段。

第四个窗格是调用堆栈断点。调用堆栈显示了执行的函数调用链,这有助于理解代码执行流。例如,如果A()方法调用B()方法,B()方法调用C()方法,则显示从A()方法到C()方法的完整执行流程。

断点选项卡显示脚本中使用的所有断点列表,用户可以通过启用或禁用、删除或添加新事件来管理这些断点:

Debugging options in Microsoft Edge

调试只能在打开F12 开发者工具窗口时启动,并且可以通过菜单栏中的F12 开发者工具窗口选项或点击F12键打开。打开窗口后,可以在 JavaScript 代码上设置断点,并在页面上执行特定操作。

下表显示了调试器工具栏中可用的一些重要选项:

|

偶像

|

选项

|

快捷键

|

描述

| | --- | --- | --- | --- | | Debugging options in Microsoft Edge | 持续 | F5F8 | 这将释放中断模式并持续到下一个断点。 | | Debugging options in Microsoft Edge | 打破 | Ctrl+班次+B | 这在下一个语句中中断。 | | Debugging options in Microsoft Edge | 踏入 | F11 | 这将进入正在调用的函数或下一条语句。 | | Debugging options in Microsoft Edge | 跨过 | F10 | 这将跳过正在调用的函数或下一条语句。 | | Debugging options in Microsoft Edge | 走出去 | 班次+F11 | 这将跳出当前函数并进入调用函数。 | | Debugging options in Microsoft Edge | 雇用新工人 | Ctrl+班次+W | 这会在创建新的 web worker 时中断。 | | Debugging options in Microsoft Edge | 异常控制 | Ctrl+Shift+E | 这可用于断开所有异常或未处理的异常。默认情况下,它设置为忽略异常。 | | Debugging options in Microsoft Edge | 断开调试器 |   | 这会断开调试器的连接,并且不会运行断点。 | | Debugging options in Microsoft Edge | 只调试我的代码 | Ctrl+J | 这将忽略第三方库的调试。 | | Debugging options in Microsoft Edge | 漂亮的印花 | Ctrl+Shift+P | 这将搜索 JavaScript 块的缩小版本并使其可读。 | | Debugging options in Microsoft Edge | 换行 | Alt+W | 这会根据内容窗格的大小对句子进行包装以进行调整。 |

Microsoft Edge 提供以下五种断点:

  • 标准
  • 有条件的
  • 追踪点
  • XHR
  • 事件

标准断点

只需从脚本代码中选择语句即可设置这些断点:

Standard breakpoints

条件断点

当满足特定条件或变量值达到特定状态时,会命中这些类型的断点。例如,我们可以将其与循环内的语句一起使用,并在计数器达到值 10 时中断执行。

点击现有断点并选择条件即可设置。。。上下文菜单中:

Conditional breakpoints

此选项打开条件断点窗口,条件设置如下图所示:

Conditional breakpoints

设置条件后,图标将更改为Conditional breakpoints

追踪点

tracepoint 用于在控制台上通过配置 tracepoint 的语句时写入消息。可通过右键单击水槽中显示的上下文菜单中的插入跟踪点选项进行设置:

Tracepoints

设置跟踪点后,图标将更改,如下所示:

Tracepoints

执行该语句时,它将在控制台窗口上打印消息,如以下屏幕截图所示:

Tracepoints

事件

Microsoft Edge 提供从断点窗格注册事件跟踪点和断点的选项。事件可以是鼠标事件、键盘事件或计时器事件。此功能在大型或复杂的 web 应用中大量使用,其中指定断点的确切位置未知。在多个位置指定事件处理程序的情况下,它也更有用。例如,如果一个页面包含五个按钮控件,并且我们需要在任何按钮引发单击事件时中断执行,那么我们只需通过断点事件指定鼠标单击事件;无论何时引发任何按钮事件,都将执行断点并将焦点放在语句上。

添加事件跟踪点

用户可以通过以下选项添加事件跟踪点:

Add event tracepoint

以下窗口显示单击鼠标时事件跟踪点的注册:

Add event tracepoint

添加事件断点

用户可以通过以下选项添加事件断点:

Add event breakpoints

以下窗口显示单击鼠标时事件断点的注册:

Add event breakpoints

XHR

与事件一样,XHR 事件也可以从浏览器的断点窗格注册。当从 JavaScript 代码发出任何 Ajax 请求时,都会调用这些事件。用户可以从以下屏幕截图中显示的图标注册 XHR 事件:

XHR

点击此事件后,会在断点窗口中添加,如下图所示:

XHR

调试类型脚本

第 5 章使用 Angular 2 和 Web API开发 ASP.NET 应用时,我们已经讨论了类型脚本以及它如何转换为最终在浏览器上运行的 JavaScript 代码。开发人员用 TypeScript 编写代码,但在浏览器上运行生成的 JavaScript 文件。当 TypeScript 文件被传输到 JavaScript 文件时,将生成一个扩展名为*.map.js的映射文件。此文件包含有关实际 TypeScript 文件和生成的 JavaScript 文件的信息。不仅如此,生成的 JavaScript 文件还包含一个关于映射文件的条目,该条目实际上告诉浏览器通过读取映射文件来加载相应的源 TypeScript 文件。

以下是从 TypeScript 传输生成的每个 JavaScript 文件时包含的条目:

//# sourceMappingURL=http://localhost:12144/todosapp/apps/createTodo.component.js.map

这可以从TSConfig.json文件通过sourceMap属性进行配置。如果sourceMap属性为true,则生成映射文件,并在生成的 JavaScript 文件中创建一个条目。此外,在 ASP.NET 核心应用中工作时,所有静态文件必须位于wwwroot文件夹中。因此,要调试 typescript,必须将所有对应的 typescript(.ts文件移动到wwwroot文件夹下的任何文件夹中,以便可以从浏览器访问该文件夹。

这是调试器窗口,在左侧显示 TypeScript 文件列表,在右上角显示用于在源文件和编译 JavaScript 版本之间切换的图标:

Debugging TypeScript

所有浏览器支持的调试器关键字

我们还可以通过debugger关键字明确强制在某个点中断控件。如果未设置断点,但指定了debugger关键字,则将启用调试并中断执行。可以从如下屏幕截图所示的代码中进行设置:

Debugger keyword supported by all browsers

总结

在本章中,我们讨论了如何测试和调试 JavaScript 应用。对于测试 JavaScript 应用,我们讨论了 Jasmine 测试套件,它可以很容易地插入 Karma,这是一个测试运行程序,可以与 Grunt 一起使用,以便从 Visual Studio任务运行程序资源管理器窗口执行。我们还讨论了 MVVM 模式的基础知识以及如何使用 Knockout JavaScript 库实现它。然后,我们修改了测试用例以使用视图模型。对于调试,我们讨论了使用 Visual Studio 调试 JavaScript 的一些技巧和技术,以及 Microsoft Edge 通过开发者工具窗口提供的使调试变得简单的功能。最后,我们还学习了一些基本主题,如 MicrosoftEdge 如何为 TypeScript 文件启用调试,以及实现调试所需的配置。