Error: Non-assignable model expression: undefined - unit-testing

I'm trying to write tests for a directive, so I'm constructing it by hand with $compile. (Yes, I know that I can use e2e tests for this, but in this case I want to test some DOM independent logic so I'm using the unit test approach.)
I have a field that I'm binding to with scope: {foo: '='}. When I try to set it on the directive's scope, I get the following error:
Error: Non-assignable model expression: undefined (directive: foo)
at Error (<anonymous>)
at $get.parentSet (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:4146:25)
at Object.<anonymous> (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:4160:23)
at Object.$get.Scope.$digest (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:7693:38)
at Object.$get.Scope.$apply (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:7894:24)
at SNAKE_CASE_REGEXP (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:930:13)
at Object.invoke (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:2788:25)
at bootstrap (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:928:12)
at angularInit (https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:904:5)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:14397:5
Reproduced in this fiddle.

In your directive you have:
scope: {
bar: '='
}
This means it's going to look on the directive element (<div foo></div>) for an attribute name "bar" and do a two-way databinding within your directive and the object specified for the attribute. So, first you need to add a bar attribute, and then you need to have something set in your scope with the name of the value of the attribute. See http://jsfiddle.net/u4BTu/6/

Another possible cause of this error is neglecting to account for Angular's normalization of the attributes. For instance, if you have the following directive:
<my-directive parameter-one="foo" parameter_two="bar"></my-directive>
With this scope declaration:
scope: {
'parameter-one': '=',
parameter_two: '=',
}
You'll get this error. To correct, use the normalized versions for the scope declaration:
scope: {
parameterOne: '=',
parameterTwo: '=',
}

Related

Prestashop - Fatal error: Undefined class constant 'self::TYPE_STRING'

I am developing a module in prestashop 1.6, i extend AdminController class, every thing is nice.but when i want to display the form that permit to add new instance an error message is displayed :
Fatal error: Undefined class constant 'self::TYPE_STRING' in C:\xampp\htdocs\prestashop\classes\controller\AdminController.php on line 1418
self::TYPE_STRING is a constant from ObjectModel, not AdminController.
I don't know why you'd want use it inside AdminController, but if really need to, change it to : ObjectModel::TYPE_STRING.
Keyword self referes to the current class you're in (in this it is AdminController)
With PHP you can create the missing constant with code like this:
class Test {
private const TYPE_STRING = 'string value';
public function getString() {
return self::TYPE_STRING;
}
}

Use rspec to test class methods are calling scopes

I have created rspec tests for my scopes (scope1, scope2 and scope3) and they pass as expected but I would also like to add some tests for a class method that I have which is what is actually called from my controller (the controller calls the scopes indirectly via this class method):
def self.my_class_method(arg1, arg2)
scoped = self.all
if arg1.present?
scoped = scoped.scope1(arg1)
end
if arg2.present?
scoped = scoped.scope2(arg2)
elsif arg1.present?
scoped = scoped.scope3(arg1)
end
scoped
end
It seems a bit redundant to run the same scope tests for each scenario in this class method when I know they already pass so I assume I really only need to ensure that different scopes are called/applied dependant on the args being passed into this class method.
Can someone advise on what this rspec test would look like.
I thought it might be something along the lines of
expect_any_instance_of(MyModel.my_class_method(arg1, nil)).to receive(:scope1).with(arg1, nil)
but that doesn't work.
I would also appreciate confirmation that this is all that's necessary to test in this situation when I've already tested the scopes anyway would be reassurring.
The Rspec code you wrote is really testing the internal implementation of your method. You should test that the method returns what you want it to return given the arguments, not that it does it in a certain way. That way, your tests will be less brittle. For example if you change what scope1 is called, you won't have to rewrite your my_class_method tests.
I would do that by creating a number of instances of the class and then call the method with various arguments and check that the results are what you expect.
I don't know what scope1 and scope2 do, so I made an example where the arguments are a name attribute for you model and the scope methods simply retrieve all models except those with that name. Obviously, whatever your real arguments and scope methods do you should put that in your tests, and you should modify the expected results accordingly.
I used the to_ary method for the expected results since the self.all call actually returns an ActiveRecord association and therefore wouldn't otherwise match the expected array. You could probably use includes and does_not_includes instead of eq, but perhaps you care about the order or something.
describe MyModel do
describe ".my_class_method" do
# Could be helpful to use FactoryGirl here
# Also note the bang (!) version of let
let!(:my_model_1) { MyModel.create(name: "alex") }
let!(:my_model_2) { MyModel.create(name: "bob") }
let!(:my_model_3) { MyModel.create(name: "chris") }
context "with nil arguments" do
let(:arg1) { nil }
let(:arg2) { nil }
it "returns all" do
expected = [my_model_1, my_model_2, my_model_3]
expect_my_class_method_to_return expected
end
end
context "with a first argument equal to a model's name" do
let(:arg1) { my_model_1.name }
let(:arg2) { nil }
it "returns all except models with name matching the argument" do
expected = [my_model_2, my_model_3]
expect_my_class_method_to_return expected
end
context "with a second argument equal to another model's name" do
let(:arg1) { my_model_1.name }
let(:arg2) { my_model_2.name }
it "returns all except models with name matching either argument" do
expected = [my_model_3]
expect_my_class_method_to_return expected
end
end
end
end
private
def expect_my_class_method_to_return(expected)
actual = described_class.my_class_method(arg1, arg2).to_ary
expect(actual).to eq expected
end
end

scope not working on Mongoid (undefined method `to_criteria')

I invoke ReleaseSchedule.next_release in other controller
and got the following error
NoMethodError (undefined method `to_criteria' for #<ReleaseSchedule:0x007f9cfafbfe70>):
app/controllers/weekly_query_controller.rb:15:in `next_release'
releae_schedule.rb
class ReleaseSchedule
scope :next_release, ->(){ ReleaseSchedule.where(:release_date.gte => Time.now).without(:_id, :created_at, :updated_at).first }
end
That's not really a scope at all, that's just a class method wrapped up to look like a scope. There are two problems:
You're saying ReleaseSchedule.where(...) so you can't chain the "scope" (i.e. ReleaseSchedule.where(...).next_release won't do what it is supposed to do).
Your "scope" ends in first so it won't return a query, it just returns a single instance.
2 is probably where your NoMethodError comes from.
If you really want it to be a scope for some reason then you'd say:
# No `first` or explicit class reference in here.
scope :next_release, -> { where(:release_date.gte => Time.now).without(:_id, :created_at, :updated_at) }
and use it as:
# The `first` goes here instead.
r = ReleaseSchedule.next_release.first
But really, you just want a class method:
def self.next_release
where(:release_date.gte => Time.now).without(:_id, :created_at, :updated_at).first
end
The scope macro is, after all, just a fancy way to build class methods. The only reason we have scope is to express an intent (i.e. to build queries piece by piece) and what you're doing doesn't match that intent.

Unit test Angular directive within directive

I'm having a real hard time running a karma unit test over an angularjs directive. Here's my setup:
var scope, ele;
var template = '<div data-my-directive data="data" config="config"></div>';
beforeEach(function () {
// Load directive's module
module('dashboard');
module('templates-dev');
// Load mock services/data (overriding real implementation)
module(function($provide) {
$provide.value("MockWidgetData", new MockWidgetData());
});
// Construct services/data to be available
// inside each testing block.
inject(function($rootScope, $compile, MockWidgetData) {
// Create a fresh scope
scope = $rootScope.$new();
ele = angular.element(template);
// Fill that scope with mock data
scope.config = MockWidgetData.config;
scope.data = MockWidgetData.data;
// Compile the element and attach our scope
$compile(ele)(scope);
// Digest the scope to trigger a scope update
// and attach our directive's link function
scope.$digest();
});
});
My directive passes 'data' and 'config' objects to its children, which happen to be other directives. The directive itself uses a templateUrl, which is why I provide the module(templates-dev): an html2js pre-compiled, angular-modularized, $templateCache'd version of my templates. Here's a sample of my directive's templateUrl:
<div id="container">
<button id="my-btn" ng-click="doSomething('parameter')"></button>
<div other-dir data="data" config="config"></div>
</div>
Here's a sample of my directive:
angular.module('dashboard').directive('myDirective', function() {
return {
restrict: 'A',
templateUrl: 'my-dir-template.html',
scope: { //
data: '=',
config: '='
},
replace: true,
link: function(scope, element, attrs) {
scope.someFunc() = { ... },
scope.someFunc1() = { ... },
});
Problem:
After $compile(ele)(scope), a .log() of the element shows the entire
DOM, including all sorts of angular.js directives and other strange
information. I would expect to see my directive's test template
mashed together with the above templateUrl.
A .log() of the scope shows the complete data and config objects, with their expected values. It also shows the functions available inside of my directive's link function, as one would expect. However, inside my test blocks, it's as if the scope object is emptied... I cannot access any of my directive's functions (they all return undefined).
I am able to capture some elements of my directive's html via ele.find("#my-btn").eq(0), but none of the normal functions work (.click(), etc.).
What am I doing wrong? Is there something wrong with the compile process? Am I structuring the test wrong? Should I try to remove the link function and replace it with a Controller? My scopes just aren't lining up, and I've been failing at this for two days now... kind of annoying.
After closer inspection... It looks like I can scope.$digest() before $compile(ele)(scope), which will correctly propagate "data" and "config" objects to the child scope. However, my scope then loses access to the functions defined in my directive's link.
You should call scope.$digest() after $compile(ele)(scope). Digest is necessary to proceed compilation of directive. Your directive has an isolated scope, that's why you can't access it functions. To get them you should try this:
var elScope = element.isolateScope();
here you'l got your elScope.someFunc();
Check this example of unit testing directives:
http://best-web-creation.com/articles/view/id/angular-js-unit-test-directive?lang=en

Multiple calls to staticExpects on mocked objects

I am tring to write test cases for my controller in cakephp, so far i have managed to mock the controller and include the auth component which is used in my controller function. the problem is it seems that i can call staticExpects only once, which means that i can define a return value for only one function call, i don't want that, i need to call staticExpects more than once within the same test case.
Here is a part of my code.
$this->TasksController = $this->generate('Tasks', array(
'components' => array('Session','Auth' => array('User'), ) ));
$this->TasksController->Auth->staticExpects($this->any())
->method('User')
->with('userID')
->will($this->returnValue(224));
$this->TasksController->Auth->staticExpects($this->any())
->method('User')
->with('accID')
->will($this->returnValue('some ID here'));
whenever i do this and run the test it gives me this error
Expectation failed for method name is equal to when invoked zero or more times
Parameter 0 for invocation AuthComponent::user('userID') does not match expected value.
Failed asserting that two strings are equal.
Please help :)
You have to specify when the static methods are called using $this->at(index).
$this->TasksController->Auth->staticExpects($this->at(1))
->method('user')
->with('userID')
->will($this->returnValue(224));
$this->TasksController->Auth->staticExpects($this->at(2))
->method('user')
->with('accID')
->will($this->returnValue('some ID here'));
If you're not sure when they are called try each expectation one by one until the error messages will give you what is called
--- Expected
+++ Actual
## ##
-'userID'
+'accID'
One last thing, the correct method name is "user" and not "User"