Testing en AngularJS
AngularJS fue uno de los primeros frameworks que apostó por pruebas automatizadas desde su diseño. Aquí cubrimos las herramientas esenciales.
Stack recomendado
- Jasmine: framework de pruebas BDD.
- Karma: lanzador de tests en navegadores reales o headless.
- angular-mocks: utilidades para inyectar dependencias y simular HTTP.
- Protractor (legacy) o Cypress para pruebas end-to-end.
Configurar Karma + Jasmine
npm install karma karma-jasmine karma-chrome-launcher jasmine-core angular-mocks --save-dev
npx karma init
karma.conf.js:
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine'],
files: [
'node_modules/angular/angular.js',
'node_modules/angular-mocks/angular-mocks.js',
'src/**/*.module.js',
'src/**/*.js',
'src/**/*.spec.js',
'src/**/*.html',
],
preprocessors: {
'src/**/*.html': ['ng-html2js'],
'src/**/!(*.spec).js': ['coverage'],
},
browsers: ['ChromeHeadless'],
reporters: ['spec', 'coverage'],
coverageReporter: {
type: 'lcov',
dir: 'coverage/',
},
});
};
Test unitarios de componentes
describe('Component: userCard', function () {
beforeEach(module('demoApp'));
let $componentController;
beforeEach(inject(function (_$componentController_) {
$componentController = _$componentController_;
}));
it('debe exponer la función select', function () {
const bindings = {user: {id: 1}, onSelect: jasmine.createSpy('onSelect')};
const ctrl = $componentController('userCard', null, bindings);
ctrl.select();
expect(bindings.onSelect).toHaveBeenCalledWith({id: 1});
});
});
Simular HTTP con $httpBackend
describe('Service: usersService', function () {
let usersService, $httpBackend;
beforeEach(module('demoApp'));
beforeEach(inject(function (_usersService_, _$httpBackend_) {
usersService = _usersService_;
$httpBackend = _$httpBackend_;
}));
afterEach(() => $httpBackend.verifyNoOutstandingExpectation());
it('debe recuperar usuarios', function () {
$httpBackend.expectGET('/api/users').respond([{id: 1, name: 'Ada'}]);
let result;
usersService.list().then(data => (result = data));
$httpBackend.flush();
expect(result.length).toBe(1);
});
});
Testing de directivas
describe('Directive: autoFocus', function () {
let $compile, $rootScope;
beforeEach(module('demoApp'));
beforeEach(inject(function (_$compile_, _$rootScope_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
}));
it('debe enfocar el elemento', function () {
const element = $compile('<input auto-focus />')($rootScope);
$rootScope.$digest();
expect(document.activeElement).toBe(element[0]);
});
});
End-to-end (E2E)
- Protractor era el estándar, pero ha quedado en mantenimiento. Si tu proyecto lo usa, puedes mantenerlo o migrar a Cypress/Playwright.
- Con Cypress:
npm install cypress --save-dev
npx cypress open
describe('Dashboard', () => {
it('debe mostrar el nombre de usuario', () => {
cy.visit('http://localhost:3000/');
cy.contains('Hola AngularJS');
});
});
Integración continua
# .github/workflows/test.yml
name: test
on: [push, pull_request]
jobs:
karma:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- run: npm ci
- run: npm test -- --watch=false
Cobertura y calidad
- Apunta a >80% de cobertura con Istanbul /
karma-coverage. - Usa ESLint con eslint-plugin-angular.
- Ejecuta
npm audity herramientas como Retire.js para detectar vulnerabilidades en dependencias legacy.
Consejos
- Los tests deben ser rápidos y aislados; usa
$httpBackendy mocks para evitar dependencias externas. - Para apps grandes, combina tests unitarios, de integración (componentes) y E2E en el pipeline.
- Documenta estrategias de debugging (
ngMock,angular.mock.inject) para facilitar onboarding.