AngularJS Unit Testing with Karma & Jasmine

โšก Tรณm tแบฏt thรดng minh

AngularJS Unit Testing with Karma and Jasmine verifies controllers, directives, and services in isolation. Karma runs specifications inside real browsers, Jasmine supplies the assertion syntax, and angular-mocks injects dependencies without a live server.

  • ๐Ÿงฑ Tooling Split: Karma is the test runner, Jasmine is the specification framework, and angular-mocks supplies dependency injection helpers.
  • โš™๏ธ ฤฦฐแปng dแบซn cร i ฤ‘แบทt: Install karma, karma-chrome-launcher, karma-jasmine, and karma-cli through npm, then generate karma.conf.js.
  • ๐Ÿ“ Configuration Rule: The files array must list angular.js, angular-mocks.js, application sources, and the test folder in that order.
  • ๐ŸŽ›๏ธ Controller Testing: Inject the $controller service, pass a mock $scope object, then assert the values the controller assigns.
  • ๐Ÿงฉ Directive Testing: Use $compile with $rootScope, call $digest, and inspect the rendered markup returned by the directive.
  • ๐ŸŒ End to End Layer: protractor drives a running application and counts repeated rows produced by ng-repeat.
  • ๐Ÿ“Œ Trแบกng thรกi hแป— trแปฃ: AngularJS reached end of life on 31 December 2021, so treat this workflow as legacy maintenance knowledge.

AngularJS Unit Testing with Karma and Jasmine

One of the most brilliant features of AngularJS is the Kiแปƒm tra khรญa cแบกnh. Khi cรกc nhร  phรกt triแปƒn tแบกi Google Khi phรกt triแปƒn AngularJS, hแป luรดn chรบ trแปng ฤ‘แบฟn viแป‡c kiแปƒm thแปญ vร  ฤ‘แบฃm bแบฃo toร n bแป™ khung AngularJS ฤ‘แปu cรณ thแปƒ kiแปƒm thแปญ ฤ‘ฦฐแปฃc.

In AngularJS, testing is normally carried out using Karma (framework). AngularJS testing can be carried out without Karma, but the Karma framework has such a brilliant functionality for testing AngularJS code, that it makes sense to use this framework.

โš ๏ธ Lฦฐu รฝ vแป phiรชn bแบฃn: AngularJS (version 1.x) reached official end of life on 31 December 2021, and Protractor was retired in August 2023. The workflow on this page remains valid for maintaining existing AngularJS 1.x applications. New projects should use modern Angular with a currently supported runner.

Giแป›i thiแป‡u & Cร i ฤ‘แบทt Karma framework

Nghiแป‡p chฦฐแป›ng lร  mแป™t cรดng cแปฅ tแปฑ ฤ‘แป™ng hรณa thแปญ nghiแป‡m created by the AngularJS team at Google. Bฦฐแป›c ฤ‘แบงu tiรชn ฤ‘แปƒ sแปญ dแปฅng Karma lร  cร i ฤ‘แบทt Karma. Karma ฤ‘ฦฐแปฃc cร i ฤ‘แบทt qua npm (lร  trรฌnh quแบฃn lรฝ gรณi ฤ‘ฦฐแปฃc sแปญ dแปฅng ฤ‘แปƒ dแป… dร ng cร i ฤ‘แบทt cรกc mรด-ฤ‘un trรชn mรกy cแปฅc bแป™).

Cร i ฤ‘แบทt nghiแป‡p chฦฐแป›ng

Viแป‡c cร i ฤ‘แบทt Karma qua npm ฤ‘ฦฐแปฃc thแปฑc hiแป‡n theo quy trรฌnh gแป“m hai bฦฐแป›c.

Bฦฐแป›c 1) Thแปฑc hiแป‡n dรฒng dฦฐแป›i ฤ‘รขy tแปซ trong dรฒng lแป‡nh

npm install karma karma-chrome-launcher karma-jasmine --save-dev

Trong ฤ‘รณ,

  1. npm is the command line utility for the node package manager used for installing custom modules on any machine. It ships with Node.js.
  2. Tham sแป‘ cร i ฤ‘แบทt hฦฐแป›ng dแบซn tiแป‡n รญch dรฒng lแป‡nh npm rแบฑng cแบงn phแบฃi cร i ฤ‘แบทt.
  3. Cรณ 3 thฦฐ viแป‡n ฤ‘ฦฐแปฃc chแป‰ ฤ‘แป‹nh trong dรฒng lแป‡nh cแบงn thiแบฟt ฤ‘แปƒ hoแบกt ฤ‘แป™ng vแป›i nghiแป‡p chฦฐแป›ng.
    • nghiแป‡p lร  thฦฐ viแป‡n cแป‘t lรตi sแบฝ ฤ‘ฦฐแปฃc sแปญ dแปฅng cho mแปฅc ฤ‘รญch thแปญ nghiแป‡m.
    • karma-chrome-launcher lร  mแป™t thฦฐ viแป‡n riรชng biแป‡t cho phรฉp trรฌnh duyแป‡t chrome nhแบญn ra cรกc lแป‡nh nghiแป‡p bรกo.
    • karma-jasmine โ€“ Cรกi nร y cร i ฤ‘แบทt Jasmine, mแป™t khung phแปฅ thuแป™c cho Karma.

Bฦฐแป›c 2) Bฦฐแป›c tiแบฟp theo lร  cร i ฤ‘แบทt tiแป‡n รญch dรฒng lแป‡nh karma. ฤiแปu nร y lร  cแบงn thiแบฟt ฤ‘แปƒ thแปฑc hiแป‡n cรกc lแป‡nh dรฒng nghiแป‡p. Tiแป‡n รญch dรฒng nghiแป‡p sแบฝ ฤ‘ฦฐแปฃc sแปญ dแปฅng ฤ‘แปƒ khแปŸi tแบกo mรดi trฦฐแปng nghiแป‡p ฤ‘แปƒ thแปญ nghiแป‡m.

ฤแปƒ cร i ฤ‘แบทt tiแป‡n รญch dรฒng lแป‡nh, hรฃy thแปฑc hiแป‡n dรฒng dฦฐแป›i ฤ‘รขy tแปซ trong dรฒng lแป‡nh

npm install -g karma-cli
  • karma-cli is used to install the command line interface for karma which will be used to write the karma commands in the command line interface. The -g flag installs it globally so that the karma command is available from any folder.

Cแบฅu hรฌnh khung Karma

Bฦฐแป›c tiแบฟp theo lร  cแบฅu hรฌnh nghiแป‡p cรณ thแปƒ ฤ‘ฦฐแปฃc thแปฑc hiแป‡n thรดng qua lแป‡nh

karma init

Sau khi thแปฑc hiแป‡n bฦฐแป›c trรชn, karma sแบฝ tแบกo tแป‡p karma.conf.js. Tแป‡p cรณ thแปƒ sแบฝ trรดng giแป‘ng nhฦฐ ฤ‘oแบกn mรฃ ฤ‘ฦฐแปฃc hiแปƒn thแป‹ bรชn dฦฐแป›i

files: [
  'node_modules/angular/angular.js',
  'node_modules/angular-mocks/angular-mocks.js',
  'lib/app.js',
  'tests/*.js'
]

Cรกc tแบญp tin cแบฅu hรฌnh แปŸ trรชn cho biแบฟt cรดng cแปฅ chแบกy karma nhแปฏng ฤ‘iแปu sau

  1. angle.js โ€“ This tells karma that your application depends on the core modules in AngularJS.
  2. angular-mocks.js โ€“ This tells karma to use the Unit Testing functionality for AngularJS from the angular-mocks.js file.
  3. Tแบฅt cแบฃ cรกc tแป‡p logic nghiแป‡p vแปฅ hoแบทc แปฉng dแปฅng chรญnh ฤ‘แปu cรณ trong thฦฐ mแปฅc lib cแปงa แปฉng dแปฅng cแปงa bแบกn.
  4. Thฦฐ mแปฅc kiแปƒm tra sแบฝ chแปฉa tแบฅt cแบฃ cรกc bร i kiแปƒm tra ฤ‘ฦกn vแป‹.

๐Ÿ’ก Mแบนo: Order matters inside the files array. angular.js must load before angular-mocks.js, and both must load before your application code, otherwise the injector is not available when the specifications run.

ฤแปƒ kiแปƒm tra xem nghiแป‡p chฦฐแป›ng cรณ hoแบกt ฤ‘แป™ng hay khรดng, hรฃy tแบกo mแป™t tแป‡p cรณ tรชn Sample.js, nhแบญp mรฃ bรชn dฦฐแป›i vร  ฤ‘แบทt nรณ vร o thฦฐ mแปฅc kiแปƒm tra.

describe('Sample test', function() {
  it('Condition is true', function() {
    expect('AngularJS').toBe('AngularJS');
  });
});

ฤoแบกn mรฃ trรชn cรณ cรกc khรญa cแบกnh sau

  1. Chแปฉc nฤƒng mรด tแบฃ ฤ‘ฦฐแปฃc sแปญ dแปฅng ฤ‘แปƒ ฤ‘ฦฐa ra mรด tแบฃ vแป bร i kiแปƒm tra. Trong trฦฐแปng hแปฃp cแปงa chรบng tรดi, chรบng tรดi ฤ‘ang ฤ‘ฦฐa ra mรด tแบฃ 'Thแปญ nghiแป‡m mแบซu' cho thแปญ nghiแป‡m cแปงa mรฌnh.
  2. Hร m 'it' ฤ‘ฦฐแปฃc sแปญ dแปฅng ฤ‘แปƒ ฤ‘แบทt tรชn cho bร i kiแปƒm tra. Trong trฦฐแปng hแปฃp cแปงa chรบng tรดi, chรบng tรดi ฤ‘แบทt tรชn cho bร i kiแปƒm tra cแปงa mรฌnh lร  'ฤiแปu kiแป‡n lร  ฤ‘รบng'. Tรชn cแปงa bร i kiแปƒm tra cแบงn phแบฃi cรณ รฝ nghฤฉa.
  3. Sแปฑ kแบฟt hแปฃp giแปฏa tแปซ khรณa 'mong ฤ‘แปฃi' vร  'toBe' cho biแบฟt giรก trแป‹ thแปฑc tแบฟ vร  mong ฤ‘แปฃi cแปงa kแบฟt quแบฃ thแปญ nghiแป‡m lร  gรฌ. Nแบฟu giรก trแป‹ thแปฑc tแบฟ vร  giรก trแป‹ mong ฤ‘แปฃi bแบฑng nhau thรฌ thแปญ nghiแป‡m sแบฝ vฦฐแปฃt qua, nแบฟu khรดng nรณ sแบฝ thแบฅt bแบกi.

Khi bแบกn thแปฑc hiแป‡n dรฒng sau tแบกi dแบฅu nhแบฏc lแป‡nh, nรณ sแบฝ thแปฑc thi tแป‡p kiแปƒm tra แปŸ trรชn

karma start

ฤแบงu ra bรชn dฦฐแป›i ฤ‘ฦฐแปฃc lแบฅy tแปซ IDE Webstorm trong ฤ‘รณ cรกc bฦฐแป›c trรชn ฤ‘รฃ ฤ‘ฦฐแปฃc thแปฑc hiแป‡n.

Cแบฅu hรฌnh cแปงa Karma Framework

  1. ฤแบงu ra xuแบฅt hiแป‡n trong Karma explorer bรชn trong Webstorm. Cแปญa sแป• nร y hiแปƒn thแป‹ viแป‡c thแปฑc hiแป‡n tแบฅt cแบฃ cรกc thแปญ nghiแป‡m ฤ‘ฦฐแปฃc xรกc ฤ‘แป‹nh trong khung nghiแป‡p vแปฅ.
  2. แปž ฤ‘รขy bแบกn cรณ thแปƒ thแบฅy mรด tแบฃ cแปงa thแปญ nghiแป‡m ฤ‘ฦฐแปฃc thแปฑc hiแป‡n ฤ‘ฦฐแปฃc hiแปƒn thแป‹ lร  โ€œThแปญ nghiแป‡m mแบซuโ€.
  3. Tiแบฟp theo, bแบกn cรณ thแปƒ thแบฅy rแบฑng bแบฃn thรขn bร i kiแปƒm tra cรณ tรชn โ€œฤiแปu kiแป‡n lร  ฤ‘รบngโ€ ฤ‘รฃ ฤ‘ฦฐแปฃc thแปฑc thi.
  4. Lฦฐu รฝ rแบฑng vรฌ tแบฅt cแบฃ cรกc bร i kiแปƒm tra ฤ‘แปu cรณ biแปƒu tฦฐแปฃng โ€œOkโ€ mร u xanh lรก cรขy bรชn cแบกnh tฦฐแปฃng trฦฐng cho viแป‡c tแบฅt cแบฃ cรกc bร i kiแปƒm tra ฤ‘แปu ฤ‘รฃ vฦฐแปฃt qua.

What is Jasmine in AngularJS Unit Testing?

Karma decides where tests run, while Jasmine decides how they are written. Jasmine is a behaviour driven specification framework that supplies the vocabulary used in every example on this page, which is why the karma-jasmine adapter is installed alongside the runner.

Jasmine contributes four building blocks:

  • describe(): Groups related specifications into a suite and accepts a readable description of the unit under test.
  • it(): Declares a single specification. The name should state the behaviour being verified rather than the method being called.
  • expect() with matchers: Compares an actual value against an expected one. Common matchers include toBe, toEqual, toContain, and toBeDefined.
  • beforeEach() and afterEach(): Run setup and teardown before and after every specification, which keeps each test independent.

Jasmine also provides spies. A spy replaces a real function with a recorded stand in, so a controller can be tested without calling a live HTTP endpoint. Because Jasmine needs no DOM and no assertion library of its own, the combination of Karma and Jasmine remains the lightest way to run AngularJS JavaScript unit tests.

Kiแปƒm tra bแป™ ฤ‘iแปu khiแปƒn AngularJS

Khung kiแปƒm tra nghiแป‡p lแปฑc cลฉng cรณ chแปฉc nฤƒng kiแปƒm tra cรกc Bแป™ ฤ‘iแปu khiแปƒn tแปซ ฤ‘แบงu ฤ‘แบฟn cuแป‘i. ฤiแปu nร y bao gแป“m viแป‡c kiแปƒm tra ฤ‘แป‘i tฦฐแปฃng $scope ฤ‘ฦฐแปฃc sแปญ dแปฅng trong Bแป™ ฤ‘iแปu khiแปƒn.

Hรฃy xem mแป™t vรญ dแปฅ vแป cรกch chรบng ta cรณ thแปƒ ฤ‘แบกt ฤ‘ฦฐแปฃc ฤ‘iแปu nร y.

Trong vรญ dแปฅ cแปงa chรบng tรดi,

ฤแบงu tiรชn chรบng ta cแบงn ฤ‘แป‹nh nghฤฉa mแป™t bแป™ ฤ‘iแปu khiแปƒn. Bแป™ ฤ‘iแปu khiแปƒn nร y sแบฝ thแปฑc hiแป‡n cรกc bฦฐแป›c ฤ‘ฦฐแปฃc ฤ‘แป cแบญp dฦฐแป›i ฤ‘รขy

  1. Tแบกo mแป™t biแบฟn ID vร  gรกn giรก trแป‹ 5 cho nรณ.
  2. Gรกn biแบฟn ID cho ฤ‘แป‘i tฦฐแปฃng $scope.

Thแปญ nghiแป‡m cแปงa chรบng tรดi sแบฝ kiแปƒm tra sแปฑ tแป“n tแบกi cแปงa bแป™ ฤ‘iแปu khiแปƒn nร y vร  cลฉng kiแปƒm tra xem biแบฟn ID cแปงa ฤ‘แป‘i tฦฐแปฃng $scope cรณ ฤ‘ฦฐแปฃc ฤ‘แบทt thร nh 5 hay khรดng.

ฤแบงu tiรชn chรบng ta cแบงn ฤ‘แบฃm bแบฃo cรกc ฤ‘iแปu kiแป‡n tiรชn quyแบฟt sau ฤ‘ฦฐแปฃc ฤ‘รกp แปฉng

Install the angular-mocks library via npm. This can be done by executing the below line in the command prompt

npm install angular-mocks --save-dev

Tiแบฟp theo lร  sแปญa ฤ‘แป•i tแป‡p karma.conf.js ฤ‘แปƒ ฤ‘แบฃm bแบฃo ฤ‘ฦฐa ฤ‘รบng tแป‡p vร o thแปญ nghiแป‡m. ฤoแบกn bรชn dฦฐแป›i chแป‰ hiแปƒn thแป‹ mแป™t phแบงn tแป‡p cแปงa karma.conf.js cแบงn ฤ‘ฦฐแปฃc sแปญa ฤ‘แป•i

files: ['lib/angular.js', 'lib/angular-mocks.js', 'lib/index.js', 'test/*.js']
  • Vแป cฦก bแบฃn, tham sแป‘ 'tแป‡p' sแบฝ cho Karma biแบฟt tแบฅt cแบฃ cรกc tแป‡p ฤ‘ฦฐแปฃc yรชu cแบงu trong quรก trรฌnh chแบกy thแปญ nghiแป‡m.
  • The angular.js and angular-mocks.js file are required to run AngularJS unit tests
  • Tแป‡p index.js sแบฝ chแปฉa mรฃ cแปงa chรบng tรดi cho bแป™ ฤ‘iแปu khiแปƒn
  • Thฦฐ mแปฅc kiแปƒm tra sแบฝ chแปฉa tแบฅt cแบฃ cรกc bร i kiแปƒm tra AngularJS cแปงa chรบng tรดi

Below is our AngularJS code which will be stored as a file Index.js in the test folder of our application.

Mรฃ bรชn dฦฐแป›i chแป‰ thแปฑc hiแป‡n nhแปฏng ฤ‘iแปu sau

  1. tแบกo mแป™t Mรด-ฤ‘un AngularJS ฤ‘ฦฐแปฃc gแปi lร  sampleApp
  2. Tแบกo bแป™ ฤ‘iแปu khiแปƒn cรณ tรชn AngularJSController
  3. Tแบกo mแป™t biแบฟn tรชn lร  ID, ฤ‘แบทt cho nรณ giรก trแป‹ 5 vร  gรกn nรณ cho ฤ‘แป‘i tฦฐแปฃng $scope
var sampleApp = angular.module('sampleApp', []);
sampleApp.controller('AngularJSController', function($scope) {
  $scope.ID = 5;
});

Khi ฤ‘oแบกn mรฃ trรชn ฤ‘ฦฐแปฃc thแปฑc thi thร nh cรดng, bฦฐแป›c tiแบฟp theo sแบฝ lร  tแบกo mแป™t Trฦฐแปng hแปฃp thแปญ nghiแป‡m ฤ‘แปƒ ฤ‘แบฃm bแบฃo mรฃ ฤ‘รฃ ฤ‘ฦฐแปฃc viแบฟt vร  thแปฑc thi ฤ‘รบng cรกch.

Mรฃ cho thแปญ nghiแป‡m cแปงa chรบng tรดi sแบฝ nhฦฐ dฦฐแป›i ฤ‘รขy.

Mรฃ sแบฝ nแบฑm trong mแป™t tแป‡p riรชng cรณ tรชn lร  ControllerTest.js, sแบฝ ฤ‘ฦฐแปฃc ฤ‘แบทt trong thฦฐ mแปฅc thแปญ nghiแป‡m. Mรฃ bรชn dฦฐแป›i chแป‰ thแปฑc hiแป‡n nhแปฏng ฤ‘iแปu chรญnh sau

  1. beforeEach function โ€“ This function is used to load our AngularJS module called โ€˜sampleAppโ€™ before the test run. Note that this is the name of the module in an index.js file.
  2. The $controller object is created as a mockup object for the controller โ€œAngularJSControllerโ€ which is defined in our index.js file. In any sort of Unit Testing, a mock object represents a dummy object which will actually be used for the testing. This mock object will actually simulate the behavior of our controller.
  3. beforeEach(inject(function(_$controller_) โ€“ ฤiแปu nร y ฤ‘ฦฐแปฃc sแปญ dแปฅng ฤ‘แปƒ ฤ‘ฦฐa ฤ‘แป‘i tฦฐแปฃng mรด phแปng vร o thแปญ nghiแป‡m cแปงa chรบng tรดi ฤ‘แปƒ nรณ hoแบกt ฤ‘แป™ng giแป‘ng nhฦฐ bแป™ ฤ‘iแปu khiแปƒn thแปฑc tแบฟ.
  4. var $scope = {}; ฤรขy lร  mแป™t ฤ‘แป‘i tฦฐแปฃng giแบฃ ฤ‘ฦฐแปฃc tแบกo cho ฤ‘แป‘i tฦฐแปฃng $scope.
  5. var controller = $controller(โ€˜AngularJSControllerโ€™, { $scope: $scope }); โ€“ Here we are checking for the existence of a controller named โ€˜AngularJSControllerโ€™. In here we are also assigning all variables from our $scope object in our controller in the Index.js file to the $scope object in our test file
  6. Cuแป‘i cรนng, chรบng tรดi so sรกnh $scope.ID vแป›i 5
describe('AngularJSController', function() {
  beforeEach(module('sampleApp'));

  var $controller;

  beforeEach(inject(function(_$controller_){
    $controller = _$controller_;
  }));

  describe('$scope.ID', function() {
    it('Check the scope object', function() {
      var $scope = {};
      var controller = $controller('AngularJSController', { $scope: $scope });
      expect($scope.ID).toEqual(5);
    });
  });
});

Bร i kiแปƒm tra trรชn sแบฝ chแบกy trong trรฌnh duyแป‡t karma vร  cho kแบฟt quแบฃ ฤ‘แบกt tฦฐฦกng tแปฑ nhฦฐ trong chแปง ฤ‘แป trฦฐแป›c.

Kiแปƒm tra cรกc chแป‰ thแป‹ AngularJS

Khung kiแปƒm thแปญ Karma cลฉng cรณ chแปฉc nฤƒng kiแปƒm thแปญ cรกc chแป‰ thแป‹ tรนy chแป‰nh. ฤiแปu nร y bao gแป“m cแบฃ mแบซu.URL's ฤ‘ฦฐแปฃc sแปญ dแปฅng trong cรกc chแป‰ thแป‹ tรนy chแป‰nh.

Hรฃy xem mแป™t vรญ dแปฅ vแป cรกch chรบng ta cรณ thแปƒ ฤ‘แบกt ฤ‘ฦฐแปฃc ฤ‘iแปu nร y.

Trong vรญ dแปฅ cแปงa chรบng tรดi, trฦฐแป›c tiรชn chรบng tรดi sแบฝ xรกc ฤ‘แป‹nh mแป™t chแป‰ thแป‹ tรนy chแป‰nh thแปฑc hiแป‡n nhแปฏng ฤ‘iแปu sau

  1. Tแบกo mแป™t mรด-ฤ‘un AngularJS cรณ tรชn sampleApp
  2. Create a custom directive with the name โ€“ guru99
  3. Tแบกo mแป™t hร m trแบฃ vแป mแป™t mแบซu cรณ thแบป tiรชu ฤ‘แป hiแปƒn thแป‹ dรฒng chแปฏ โ€œฤรขy lร  Thแปญ nghiแป‡m AngularJSโ€.
var sampleApp = angular.module('sampleApp', []);
sampleApp.directive('guru99', function () {
  return {
    restrict: 'E',
    replace: true,
    template: '<h1>This is AngularJS Testing</h1>'
  };
});

Khi ฤ‘oแบกn mรฃ trรชn ฤ‘ฦฐแปฃc thแปฑc thi thร nh cรดng, bฦฐแป›c tiแบฟp theo sแบฝ lร  tแบกo mแป™t trฦฐแปng hแปฃp thแปญ nghiแป‡m ฤ‘แปƒ ฤ‘แบฃm bแบฃo mรฃ ฤ‘รฃ ฤ‘ฦฐแปฃc viแบฟt vร  thแปฑc thi ฤ‘รบng cรกch. Mรฃ cho thแปญ nghiแป‡m cแปงa chรบng tรดi sแบฝ nhฦฐ dฦฐแป›i ฤ‘รขy

Mรฃ sแบฝ nแบฑm trong mแป™t tแป‡p riรชng cรณ tรชn lร  DirectiveTest.js, sแบฝ ฤ‘ฦฐแปฃc ฤ‘แบทt trong thฦฐ mแปฅc thแปญ nghiแป‡m. Mรฃ bรชn dฦฐแป›i chแป‰ thแปฑc hiแป‡n nhแปฏng ฤ‘iแปu chรญnh sau

  1. beforeEach function โ€“ This function is used to load our AngularJS module called โ€˜sampleAppโ€™ before the test run.
  2. The $compile service is used to compile the directive. This service is mandatory and needs to be declared so that AngularJS can use it to compile our custom directive.
  3. The $rootScope is the primary scope of any AngularJS application. We have seen the $scope object of the controller in earlier chapters. Well, the $scope object is the child object of the $rootScope object. The reason this is declared here is because we are making a change to an actual HTML tag in the DOM via our custom directive. Hence, we need to use the $rootScope service which actually listens or knows when any change happens from within an HTML document.
  4. var element = $compile(โ€œ<guru99></guru99>โ€)($rootScope) โ€“ This is used to check whether our directive gets injected as it should. The directive is registered with the camel case name guru99, so AngularJS matches the lowercase element <guru99> in the markup. Hence this statement is used to make that check.
  5. expect(element.html()).toContain(โ€œThis is AngularJS Testingโ€) โ€“ This is used to instruct the expect function that it should find the element(in our case the h1 tag) to contain the innerHTML text of โ€œThis is AngularJS Testingโ€.
describe('Unit testing directives', function() {
  var $compile,
      $rootScope;
  beforeEach(module('sampleApp'));

  beforeEach(inject(function(_$compile_, _$rootScope_){
    $compile = _$compile_;
    $rootScope = _$rootScope_;
  }));

  it('Check the directive', function() {
    // Compile a piece of HTML containing the directive
    var element = $compile("<guru99></guru99>")($rootScope);
    $rootScope.$digest();
    expect(element.html()).toContain("This is AngularJS Testing");
  });
});

Bร i kiแปƒm tra trรชn sแบฝ chแบกy trong trรฌnh duyแป‡t karma vร  cho kแบฟt quแบฃ ฤ‘แบกt tฦฐฦกng tแปฑ nhฦฐ trong chแปง ฤ‘แป trฦฐแป›c.

End to End Testing AngularJS applications

Khung kiแปƒm thแปญ Karma cรนng vแป›i mแป™t khung gแปi lร  ProtracTor cรณ chแปฉc nฤƒng kiแปƒm thแปญ แปฉng dแปฅng web tแปซ ฤ‘แบงu ฤ‘แบฟn cuแป‘i.

Vรฌ vแบญy, nรณ khรดng chแป‰ kiแปƒm tra cรกc lแป‡nh vร  bแป™ ฤ‘iแปu khiแปƒn mร  cรฒn kiแปƒm tra bแบฅt kแปณ thแปฉ gรฌ khรกc cรณ thแปƒ xuแบฅt hiแป‡n trรชn trang HTML.

Hรฃy xem mแป™t vรญ dแปฅ vแป cรกch chรบng ta cรณ thแปƒ ฤ‘แบกt ฤ‘ฦฐแปฃc ฤ‘iแปu nร y.

Trong vรญ dแปฅ bรชn dฦฐแป›i, chรบng ta sแบฝ cรณ mแป™t แปฉng dแปฅng AngularJS tแบกo bแบฃng dแปฏ liแป‡u bแบฑng cรกch sแปญ dแปฅng lแป‡nh ng-repeat.

  1. Trฦฐแป›c tiรชn, chรบng tรดi tแบกo mแป™t biแบฟn cรณ tรชn lร  โ€œhฦฐแป›ng dแบซnโ€ vร  gรกn cho nรณ mแป™t sแป‘ cแบทp khรณa-giรก trแป‹ trong mแป™t bฦฐแป›c. Mแป—i cแบทp khรณa-giรก trแป‹ sแบฝ ฤ‘ฦฐแปฃc sแปญ dแปฅng lร m dแปฏ liแป‡u khi hiแปƒn thแป‹ bแบฃng. Biแบฟn hฦฐแป›ng dแบซn sau ฤ‘รณ ฤ‘ฦฐแปฃc gรกn cho ฤ‘แป‘i tฦฐแปฃng phแบกm vi ฤ‘แปƒ cรณ thแปƒ truy cแบญp nรณ tแปซ chแบฟ ฤ‘แป™ xem cแปงa chรบng tรดi.
  2. ฤแป‘i vแป›i mแป—i hร ng dแปฏ liแป‡u trong bแบฃng, chรบng tรดi ฤ‘ang sแปญ dแปฅng lแป‡nh ng-repeat. Lแป‡nh nร y ฤ‘i qua tแปซng cแบทp khรณa-giรก trแป‹ trong ฤ‘แป‘i tฦฐแปฃng phแบกm vi hฦฐแป›ng dแบซn bแบฑng cรกch sแปญ dแปฅng biแบฟn ptutor.
  3. Cuแป‘i cรนng, chรบng tรดi ฤ‘ang sแปญ dแปฅng tag cรนng vแป›i cรกc cแบทp giรก trแป‹ khรณa (ptutor.Name vร  ptutor.Description) ฤ‘แปƒ hiแปƒn thแป‹ dแปฏ liแป‡u bแบฃng.
<table>
  <tr ng-repeat="ptutor in tutorial">
    <td>{{ ptutor.Name }}</td>
    <td>{{ ptutor.Description }}</td>
  </tr>
</table>
</div>
<script type="text/javascript">
var app = angular.module('DemoApp', []);
app.controller('DemoController', function($scope) {
  $scope.tutorial = [
    {Name: "Controllers", Description: "Controllers in action"},
    {Name: "Models", Description: "Models and binding data"},
    {Name: "Directives", Description: "Flexibility of Directives"}
  ];
});

Khi ฤ‘oแบกn mรฃ trรชn ฤ‘ฦฐแปฃc thแปฑc thi thร nh cรดng, bฦฐแป›c tiแบฟp theo sแบฝ lร  tแบกo mแป™t trฦฐแปng hแปฃp thแปญ nghiแป‡m ฤ‘แปƒ ฤ‘แบฃm bแบฃo mรฃ ฤ‘รฃ ฤ‘ฦฐแปฃc viแบฟt vร  thแปฑc thi ฤ‘รบng cรกch. Mรฃ cho thแปญ nghiแป‡m cแปงa chรบng tรดi sแบฝ nhฦฐ dฦฐแป›i ฤ‘รขy

Thแปญ nghiแป‡m cแปงa chรบng tรดi thแปฑc sแปฑ sแบฝ kiแปƒm tra lแป‡nh ng-repeat vร  ฤ‘แบฃm bแบฃo rแบฑng nรณ chแปฉa 3 hร ng dแปฏ liแป‡u nhฦฐ vรญ dแปฅ trรชn.

ฤแบงu tiรชn chรบng ta cแบงn ฤ‘แบฃm bแบฃo cรกc ฤ‘iแปu kiแป‡n tiรชn quyแบฟt sau ฤ‘ฦฐแปฃc ฤ‘รกp แปฉng

Cร i ฤ‘แบทt chuyรชn nghiแป‡ptracCร i ฤ‘แบทt thฦฐ viแป‡n Tor thรดng qua npm. Cรณ thแปƒ thแปฑc hiแป‡n bแบฑng cรกch chแบกy dรฒng lแป‡nh sau trong cแปญa sแป• lแป‡nh:

npm install -g protractor

Mรฃ cho thแปญ nghiแป‡m cแปงa chรบng tรดi sแบฝ nhฦฐ dฦฐแป›i ฤ‘รขy.

Mรฃ sแบฝ nแบฑm trong mแป™t tแป‡p riรชng cรณ tรชn CompleteTest.js, sแบฝ ฤ‘ฦฐแปฃc ฤ‘แบทt trong thฦฐ mแปฅc thแปญ nghiแป‡m. Mรฃ bรชn dฦฐแป›i chแป‰ thแปฑc hiแป‡n nhแปฏng ฤ‘iแปu chรญnh sau

  1. Chแปฉc nฤƒng trรฌnh duyแป‡t ฤ‘ฦฐแปฃc cung cแบฅp bแปŸi chuyรชn gia.tracThฦฐ viแป‡n Tor giแบฃ ฤ‘แป‹nh rแบฑng แปฉng dแปฅng AngularJS cแปงa chรบng ta (vแป›i ฤ‘oแบกn mรฃ ฤ‘ฦฐแปฃc hiแปƒn thแป‹ แปŸ trรชn) ฤ‘ang chแบกy trรชn trang web cแปงa chรบng ta. URL โ€“ http://localhost:8080/Guru99 /
  2. var list = element.all(by.repeater(โ€˜ptutor in tutorialโ€™)); -This line of code is actually fetching the ng-repeat directive which is populated by the code โ€˜ptutor in tutorialโ€™. The element and by.repeater are special keywords provided by the protracThฦฐ viแป‡n Tor cho phรฉp chรบng ta lแบฅy thรดng tin chi tiแบฟt vแป chแป‰ thแป‹ ng-repeat.
  3. mong ฤ‘แปฃi(list.count()).toEqual(3); โ€“ Cuแป‘i cรนng, chรบng ta ฤ‘ang sแปญ dแปฅng hร m mong ฤ‘แปฃi ฤ‘แปƒ thแบฅy rแบฑng chรบng ta thแปฑc sแปฑ nhแบญn ฤ‘ฦฐแปฃc 3 mแปฅc ฤ‘ฦฐแปฃc ฤ‘iแปn vร o bแบฃng do lแป‡nh ng-repeat.
describe('Unit testing end to end', function() {
  beforeEach(function() {
    browser.get('http://localhost:8080/Guru99/');
  });

  it('Check the ng directive', function() {
    var list = element.all(by.repeater('ptutor in tutorial'));
    expect(list.count()).toEqual(3);
  });
});

Bร i kiแปƒm tra trรชn sแบฝ chแบกy trong trรฌnh duyแป‡t karma vร  cho kแบฟt quแบฃ ฤ‘แบกt tฦฐฦกng tแปฑ nhฦฐ trong chแปง ฤ‘แป trฦฐแป›c.

Karma vs Jasmine vs Protractor: Key Differences

The three tools used across this page are often confused because they appear in the same command line. Each one occupies a different layer of the testing stack, as the table below makes clear.

Tham sแป‘ Karma Jasmine protractor
Phรขn loแบกi ngฦฐแปi chแบกy thแปญ Specification framework End to end automation framework
Cรดng viแป‡c chรญnh Launches browsers and reports results Provides describe, it, and expect Drives a live application in a real browser
Cแบฅp ฤ‘แป™ kiแปƒm tra ฤ‘ฦกn vแป‹ vร  hแป™i nhแบญp Unit and integration Kแบฟt thรบc ฤ‘แบฟn kแบฟt thรบc
Needs a running server Khรดng Khรดng Cรณ
Tแบญp tin cแบฅu hรฌnh nghiแป‡p chฦฐแป›ng.conf.js None, it runs inside a runner vรฌtractor.conf.js
Tรฌnh trแบกng hiแป‡n tแบกi Deprecated, maintenance only tรญch cแปฑc duy trรฌ Retired in August 2023

In short, Jasmine writes the test, Karma executes it, and Protractor extends the same Jasmine syntax to a fully rendered page.

Best Practices for AngularJS Unit Testing

A small set of habits keeps an AngularJS suite fast and trustworthy as the application grows.

  1. Test one unit at a time. Load only the module under test inside beforeEach, and mock every collaborator so a failure points at a single file.
  2. Never call a real backend. Use the $httpBackend service from angular-mocks to return canned responses. Tests then run offline and produce identical results on every machine.
  3. Keep specification names behavioural. A name such as โ€œreturns 5 when the controller initialisesโ€ reads better in a report than โ€œtest1โ€.
  4. Always flush the digest cycle. Call $rootScope.$digest() after changing scope data, otherwise bindings and watchers never update and assertions fail for the wrong reason.
  5. Measure coverage, but judge it carefully. Add karma-coverage to see untested branches. High coverage with weak assertions still hides defects.
  6. Run the suite in continuous integration. Use a headless Chrome launcher so the same specifications execute on every commit rather than only on a developer machine.

Applying these rules turns the examples above from isolated demonstrations into a regression safety net for a legacy AngularJS codebase. For the wider picture, see the AngularJS tutorial series.

Cรขu Hoฬ‰i Thฦฐฦกฬ€ng Gฤƒฬฃp

The module holding that provider was not loaded. Add it inside beforeEach(module(โ€˜yourModuleโ€™)) and confirm angular-mocks.js is listed in karma.conf.js after angular.js, otherwise the injector cannot resolve the dependency.

Install karma-chrome-launcher and set the browsers option to ChromeHeadless in karma.conf.js. The suite then runs inside continuous integration pipelines and containers where no display server is available.

Yes. AI coding assistants read a controller and draft Jasmine specifications with mock scopes and matchers. Review the output carefully, because generated assertions often restate the implementation instead of verifying the intended behaviour.

Yes. AI tools translate Jasmine specifications into Jest or Vitest syntax and flag angular-mocks calls that have no direct equivalent. Manual verification remains essential, since dependency injection patterns rarely convert cleanly.

Most teams target seventy to eighty percent statement coverage on controllers and services. Chasing a higher figure usually means testing templates and third party libraries, which adds maintenance cost without catching real defects.

Tรณm tแบฏt bร i viแบฟt nร y vแป›i: