Controle testável ativado em AngularJS

Adotei o guia de estilo AngularJS de John Papa recentemente e tem funcionado muito bem para mim até agora. Uma de suas regras de que não gosto são as promessas de ativação do controlador :

function AvengersViewModel(dataService) {
var viewModel = this;

viewModel
.avengers = [];
viewModel
.save = save;

activate
();

function activate() {
return dataService.getAvengers().then(function (data) {
viewModel
.avengers = data;
return viewModel.avengers;
});
}

function save() {
// (...)
}
}

Gosto do fato de que o código de ativação está em sua própria função, mas invocá-lo imediatamente é praticamente o mesmo que ter lógica no construtor . Isso significa que, se você quiser fazer o teste de unidade do método, saveprecisará verificar dataService.getAvengersse o stub foi feito corretamente.

Eu queria expor activatee receber uma chamada de outra pessoa em vez de AvengersViewModel:

function AvengersViewModel(dataService) {
var viewModel = this;

// (...)

// Expose it
viewModel
.activate = activate;

function activate() {
// (...)
}

// (...)
}

Mas quem poderia ser esse alguém?

A abordagem ingênua

Eu sabia ngInit, mas também sabia que não deveria usá-lo. Isso não me impediu de tentar:

function avengers() {
return {
scope
: {},
template
: '<div ng-init="viewModel.activate()">The avengers directive</div>',
controller
: 'AvengersViewModel',
controllerAs
: 'viewModel'
};
}

Isso funcionou, mas não parecia certo.

Uma abordagem melhor

Eu me lembrei de ver alguém usando o requirepara disponibilizar o controlador da própria diretiva como o quarto parâmetro da linkfunção. Aparentemente, você pode até omitir a requirepropriedade por completo e terá acesso à instância do controlador da diretiva:

function avengers() {
return {
scope
: {},
template
: '<div>The avengers directive</div>',
controller
: 'AvengersViewModel',
controllerAs
: 'viewModel',
link
: function (scope, element, attributes, viewModel) {
viewModel
.activate();
}
};
}

Agora posso testar a unidade corretamente em meus modelos de visualização e ter os benefícios das Promessas de ativação do controlador . Impressionante!