django: Testing POST-based views with json objects - ajax

I have a django application with several views that accept json objects via POST requests. The json objects are medium-complex with a few layers of nesting, so I'm using the json library to parse raw_post_data, as shown here:
def handle_ajax_call(request):
post_json = json.loads(request.raw_post_data)
... (do stuff with json query)
Next, I want to write tests for these views. Unfortunately, I can't figure out how to pass the json object to the Client. Here's a simplest-case version of my code:
def test_ajax_call(self):
c = Client()
call_command('loadfixtures', 'temp-fixtures-1') #Custom command to populate the DB
J = {
some_info : {
attr1 : "AAAA",
attr2 : "BBBB",
list_attr : [ "x", "y", "z" ]
},
more_info : { ... },
info_list : [ 1, 22, 23, 24, 5, 26, 7 ]
}
J_string = json.dumps(J)
response = c.post('/ajax/call/', data=J_string )
When I run the test, it fails with:
AttributeError: 'str' object has no attribute 'items'
How can I pass the JSON object in the Client.post method?

The documentation seems to imply that if you pass a content_type parameter to client.post, it will treat the data value as a document and POST it directly. So try this:
response = c.post('/ajax/call/', content_type='application/json', data=J_string)

Related

Mocha and Chai: JSON contains/includes certain text

Using Mocha and Chai, I am trying to check whether JSON array contains a specific text. I tried multiple things suggested on this site but none worked.
await validatePropertyIncludes(JSON.parse(response.body), 'scriptPrivacy');
async validatePropertyIncludes(item, propertyValue) {
expect(item).to.contain(propertyValue);
}
Error that I getting:
AssertionError: expected [ Array(9) ] to include 'scriptPrivacy'
My response from API:
[
{
"scriptPrivacy": {
"settings": "settings=\"foobar\";",
"id": "foobar-notice-script",
"src": "https://foobar.com/foobar-privacy-notice-scripts.js",
}
You can check if the field is undefined.
If field exists in the JSON object, then won't be undefined, otherwise yes.
Using filter() expresion you can get how many documents don't get undefined.
var filter = object.filter(item => item.scriptPrivacy != undefined).length
If attribute exists into JSON file, then, variable filter should be > 0.
var filter = object.filter(item => item.scriptPrivacy != undefined).length
//Comparsion you want: equal(1) , above(0) ...
expect(filter).to.equal(1)
Edit:
To use this method from a method where you pass attribute name by parameter you can use item[propertyName] because properties into objects in node can be accessed as an array.
So the code could be:
//Call function
validatePropertyIncludes(object, 'scriptPrivacy')
function validatePropertyIncludes(object, propertyValue){
var filter = object.filter(item => item[propertyValue] != undefined).length
//Comparsion you want: equal(1) , above(0) ...
expect(filter).to.equal(1)
}

Enforce that a Grape Entity always returns an array?

How can I enforce that my Grape Entity always returns an array (collection) even if its just a singular object? I have heard that some people create a helper method that gets called inside their endpoint, but I have not found any examples of anyone doing that, online.
The default functionality of an Entity is that it returns an object if only a single document (mongoid object) is returned. If a collection of documents is returned then it returns an array, I dont want my client application having to do a check every time to see if an object or an array got returned from my API.
## Resource (HTTP Endpoint)
desc 'List departments a user can and cannot access'
params do
requires :user_id
end
get :department_access do
#user = BACKBONE::User.find(#access_key.user_id)
requires_admin!
user = BACKBONE::User.find(params[:user_id])
can_access = BACKBONE::Department.user_can_access(user)
no_access = BACKBONE::Department.user_cannot_access(user)
present_success can_access
present :can_access, can_access, with: BACKBONE::Entities::DepartmentBase
present :no_access, no_access, with: BACKBONE::Entities::DepartmentBase
end
-
## Entity
module BACKBONE
module Entities
class DepartmentBase < BACKBONE::Entities::Mongoid
expose :name
expose :prefix
with_options(format_with: :mongo_id) do
expose :company_id
end
end
end
end
JSON Response
{
"status": "success",
"request_time": 0.009812,
"records": 1,
"can_access": {
"id": "59699d1a78cee4f8d07528fc",
"created_at": "2017-07-14T21:42:02.666-07:00",
"updated_at": "2017-07-14T21:42:02.666-07:00",
"name": "Tenant Improvement",
"prefix": "CACC",
"company_id": "596927fb670f6eec21c4f409"
},
"no_access": {
"id": "59699cca78cee4f8d07528fb",
"created_at": "2017-07-14T21:40:42.005-07:00",
"updated_at": "2017-07-14T21:40:42.005-07:00",
"name": "Field Operations",
"prefix": "CACC",
"company_id": "596927fb670f6eec21c4f409"
}
}
a coworker and I came up with a solution with a helper, create a helper method that always returns an array:
def present_array(key, data, entity)
d = (data.class.respond_to? :count) ? [data] : data
d = [] if d.nil?
present key, d, entity
end

How do i serialize objects during enrichment with stream-django and django rest framework?

Im using stream-django with django REST framework and the enriched activities are throwing "not JSON serializable" on the objects returned from enrichment, which is as expected as they have not gone through any serializing.
How do i customize the enrichment process so that it returns a serialized object from my drf serializer and not the object itself?
Some example data, not enriched:
"is_seen": false,
"is_read": false,
"group": "19931_2016-04-04",
"created_at": "2016-04-04T08:53:42.601",
"updated_at": "2016-04-04T11:33:26.140",
"id": "0bc8c85a-fa59-11e5-8080-800005683205",
"verb": "message",
"activities": [
{
"origin": null,
"verb": "message",
"time": "2016-04-04T11:33:26.140",
"id": "0bc8c85a-fa59-11e5-8080-800005683205",
"foreign_id": "chat.Message:6",
"target": null,
"to": [
"notification:1"
],
"actor": "auth.User:1",
"object": "chat.Message:6"
}
The view:
def get(self, request, format=None):
user = request.user
enricher = Enrich()
feed = feed_manager.get_notification_feed(user.id)
notifications = feed.get(limit=5)['results']
enriched_activities=enricher.enrich_aggregated_activities(notifications)
return Response(enriched_activities)
I solved it by doing the following:
property tag on the model that returns the serializer class
#property
def activity_object_serializer_class(self):
from .serializers import FooSerializer
return FooSerializer
Then used this to serialize the enriched activities. Supports nesting.
#staticmethod
def get_serialized_object_or_str(obj):
if hasattr(obj, 'activity_object_serializer_class'):
obj = obj.activity_object_serializer_class(obj).data
else:
obj = str(obj) # Could also raise exception here
return obj
def serialize_activities(self, activities):
for activity in activities:
for a in activity['activities']:
a['object'] = self.get_serialized_object_or_str(a['object'])
# The actor is always a auth.User in our case
a['actor'] = UserSerializer(a['actor']).data
return activities
and the view:
def get(self, request, format=None):
user = request.user
enricher = Enrich()
feed = feed_manager.get_notification_feed(user.id)
notifications = feed.get(limit=5)['results']
enriched_activities = enricher.enrich_aggregated_activities(notifications)
serialized_activities = self.serialize_activities(enriched_activities)
return Response(serialized_activities)
The enrich step replaces string references into full Django model instances.
For example: the string "chat.Message:6" is replaced with an instance of chat.models.Message (same as Message.objects.get(pk=6)).
By default DRF does not know how to serialize Django models and fails with a serialization error. Luckily serializing models is a very simple task when using DRF. There is a built-in serializer class that is specific to Django models (serializers.ModelSerializer).
The documentation of DRF explains this process in detail here: http://www.django-rest-framework.org/api-guide/serializers/#modelserializer.
In your case you probably need to use nested serialization and make the serialization of the object field smart (that field can contain references to different kind of objects).
There is an open issue about this on Github: https://github.com/GetStream/stream-django/issues/38. Ideally this is something the library will provide as helper/example, so any code contribution / input will help making that happen.

make json from params hash

I am trying to call API and pass data to it from the form in my view to controller and then call API with post method.
What I get in params is:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"kLLaVRc6kcndkfB1nkntSTzGCg95CMCT1UvEncqwLgc=",
"score_sheet"=>{
"score_sheet_master"=>{
"issue_date(1i)"=>"2014", "issue_date(2i)"=>"6", "issue_date(3i)"=>"27"},
"print_date(1i)"=>"2014", "print_date(2i)"=>"6", "print_date(3i)"=>"27", "product_id"=>"2", "pull_id"=>"2", "press_run_id"=>"1", "total_section"=>"2",
"score_sheet_sections_attributes"=>{
"0"=>{"section_name"=>"A", "total_pages"=>"2", "color_pages"=>"1", "_destroy"=>"false"},
"1"=>{"section_name"=>"B", "total_pages"=>"1", "color_pages"=>"", "_destroy"=>"false"}},
"color_pages_rated"=>"1", "bw_pages_rated"=>"2", "foreman_id"=>"", "pic_id"=>""},
"score_sheet_master"=>{
"press_id"=>"1"},
"commit"=>"Create Score sheet"}
I want this Hash to be converted into the Following JSON which APIs accept. i-e.
{
"score_sheet": {
"score_sheet_master": {
"issue_date": "2014-06-25",
"press_id": "1"
},
"print_date": "2014-06-23",
"product_id": 1,
"pull_id": 2,
"press_run_id": 1,
"total_section": 2,
"score_sheet_sections_attributes": [
{
"section_name": "A",
"total_pages": 3,
"color_pages": "2,3",
"id": 9
},
{
"section_name": "B",
"total_pages": 1,
"color_pages": "1",
"id": 10
},
{
"section_name": "C",
"total_pages": 2,
"color_pages": "2"
}
],
"pic_id": 1,
"foreman_id": 1
}
}
Some the fields in JSON might be missing or may be more than the HASH but I don't have concern with that I will handle them personally the main issue is to convert this params Hash to the required JSON. Hold On I have implemented the date conversion thing that is working fine. but don't know how to convert score_sheet_sections_attributes array format to the required format.
Oh Got it myself:
sections = []
params["score_sheet"]["score_sheet_sections_attributes"].each {|k,v| sections << v}
params["score_sheet"]["score_sheet_sections_attributes"] = sections
Which gives:
{"utf8"=>"✓", "authenticity_token"=>"kLLaVRc6kcndkfB1nkntSTzGCg95CMCT1UvEncqwLgc=", "score_sheet"=>{"score_sheet_master"=>{"issue_date(1i)"=>"2014", "issue_date(2i)"=>"6", "issue_date(3i)"=>"27"}, "print_date(1i)"=>"2014", "print_date(2i)"=>"6", "print_date(3i)"=>"27", "product_id"=>"2", "pull_id"=>"2", "press_run_id"=>"1", "total_section"=>"2", "score_sheet_sections_attributes"=>[{"section_name"=>"A", "total_pages"=>"2", "color_pages"=>"1", "_destroy"=>"false"}, {"section_name"=>"B", "total_pages"=>"1", "color_pages"=>"", "_destroy"=>"false"}], "color_pages_rated"=>"1", "bw_pages_rated"=>"2", "foreman_id"=>"", "pic_id"=>""}, "score_sheet_master"=>{"press_id"=>"1"}, "commit"=>"Create Score sheet"}
and for dates I have another logic implemented and all done.

How do i send JsonObject with nested values as Post request in REST assured

I am using rest assured -https://code.google.com/p/rest-assured/wiki/Usage
My JsonObject looks like this
{
"id": "12",
"employeeInfo": null,
"employerInfo": null,
"checkDate": 1395093997218,
"netAmount": {
"amount": 70,
"currency": "USD"
},
"moneyDistributionLineItems": [
{
"mAmount": 100,
"employeeBankAccountId": "BankAccount 1"
}
],
}
how can i send this as part of parameters using REST-assured POST?
I have tried
given().param("key1", "value1").param("key2", "value2").when().post("/somewhere").then().
body(containsString("OK"));
but that is not scalable for HUGE objects with nested values. Is there a better approach?
You just send the JSON document in the body. For example if you have your JSON document in a String called myJson then you can just do like this:
String myJson = ..
given().contentType(JSON).body(myJson).when().post("/somewhere"). ..
You can also use a POJO, input stream and byte[] instead of a String.
URL file = Resources.getResource("PublishFlag_False_Req.json");
String myJson = Resources.toString(file, Charsets.UTF_8);
Response responsedata = given().header("Authorization", AuthorizationValue)
.header("X-App-Client-Id", XappClintIDvalue)
.contentType("application/vnd.api+json")
.body(myJson)
.with()
.when()
.post(dataPostUrl);

Resources