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.

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.
- Trong AngularJS, chรบng ta cรณ thแป thแปฑc hiแปn Kiแปm tra ฤฦกn vแป riรชng cho bแป ฤiแปu khiแปn vร chแป thแป.
- Chรบng ta cลฉng cรณ thแป thแปฑc hiแปn thแปญ nghiแปm tแปซ ฤแบงu ฤแบฟn cuแปi of AngularJS, which is testing from a user perspective.
โ ๏ธ 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 ฤรณ,
- npm is the command line utility for the node package manager used for installing custom modules on any machine. It ships with Node.js.
- 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.
- 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
- angle.js โ This tells karma that your application depends on the core modules in AngularJS.
- angular-mocks.js โ This tells karma to use the Unit Testing functionality for AngularJS from the angular-mocks.js file.
- 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.
- 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
- 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.
- 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.
- 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.
- ฤแบง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แปฅ.
- แป ฤรข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โ.
- 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.
- 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
- Tแบกo mแปt biแบฟn ID vร gรกn giรก trแป 5 cho nรณ.
- 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
- tแบกo mแปt Mรด-ฤun AngularJS ฤฦฐแปฃc gแปi lร sampleApp
- Tแบกo bแป ฤiแปu khiแปn cรณ tรชn AngularJSController
- 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
- 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.
- 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.
- 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แบฟ.
- var $scope = {}; ฤรขy lร mแปt ฤแปi tฦฐแปฃng giแบฃ ฤฦฐแปฃc tแบกo cho ฤแปi tฦฐแปฃng $scope.
- 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
- 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
- Tแบกo mแปt mรด-ฤun AngularJS cรณ tรชn sampleApp
- Create a custom directive with the name โ guru99
- 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
- beforeEach function โ This function is used to load our AngularJS module called โsampleAppโ before the test run.
- 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.
- 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.
- 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.
- 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.
- 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.
- ฤแป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.
- 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
- 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 /
- 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.
- 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.
- 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.
- 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.
- Keep specification names behavioural. A name such as โreturns 5 when the controller initialisesโ reads better in a report than โtest1โ.
- 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.
- Measure coverage, but judge it carefully. Add karma-coverage to see untested branches. High coverage with weak assertions still hides defects.
- 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.

