Specify response.request.responseURL in moxios - javascript

I'm currently trying to write some functionality that requires the response.request.responseURL value to be set when axios handles the response. However, I can't seem to set this value with moxios. Here's what my test looks like:
it('resets list selection if input contents were replaced', (done) => {
component.currently_selected_list_value = 10;
component.last_called_url = 'henkiehoutman';
let input = domElt.querySelector('input');
ReactTestUtils.Simulate.change(input);
moxios.wait(() => {
let request = moxios.requests.mostRecent();
request.respondWith({
status: 200,
response: [{
customer_info_customers: ['', '', '', '', ''],
domain_info_customers: {},
}],
request: {responseURL: 'banaan'}
}).then(() => {
// The contents were replaced, so it's best to forget whatever our selection was.
expect(component.currently_selected_list_value).toEqual(-1);
done();
});
});
});
This is what my actual application looks like:
onChange (event) {
return axios.get(
this.props.ApiUrl + encodeURIComponent(event.target.value)
).then(
(response) => {
let response_url = response.request.responseURL; // This is the value I want to set manually.
if(this.shouldHandleResponse(response_url)){
this.last_called_url = response_url;
let data = response.data;
this.setState({results: data, dropdown: data.length > 0});
if ( this.currently_selected_list_value > max_index) {
this.currently_selected_list_value = max_index;
}
}
}
);
},
However, when I log what this value is, it just says undefined. And this is what the actual response.request value is (put it in a quote so it's a bit more readable):
LOG: Request{resolve: function (a) { ... }, reject: function (a) { ... }, config: Object{adapter: function mockAdapter(config) { ... }, transformRequest: Object{0: ...}, transformResponse: Object{0: ...}, timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, validateStatus: function validateStatus(status) { ... }, headers: Object{Accept: ..., X-CSRFToken: ...}, method: 'get', url: 'my_api_url/', data: undefined}, headers: Object{Accept: 'application/json, text/plain, /', X-CSRFToken: 'my_csrf_token'}, url: 'my_api_url/', timeout: 0, withCredentials: false, responseType: undefined}
This breaks my application, because a responseURL should always be defined. It looks like it's overwriting the request I defined in moxios. This is not necessarily a bad thing, because I assume it needs these things to function properly. However, it would be nice if I could add some values to this request.
So; How do I add a responseURL value to this request in moxios?

Turns out that it's not possible to set the responseURL because of the way I chained it to respondWith(). After checking this function in the moxios source code I saw that the values you pass in here really only have to do with actual data being returned, not an actual response object.
I also saw that the respondWith() function returns a Promise object, which is quite logical. I figured that I should not set anything on the Promise, but on the actual request. So I assigned the returned Promise to a promise variable and unchained the .then() part of the test. I set the request'sresponseURL after that. Then I called promise.then() again to assert that my test has passed.
Here is what I eventually went for:
it('resets list selection if input contents were replaced', (done) => {
component.currently_selected_list_value = 10;
component.last_called_url = 'henkiehoutman';
let input = domElt.querySelector('input');
ReactTestUtils.Simulate.change(input);
moxios.wait(() => {
let request = moxios.requests.mostRecent();
let promise = request.respondWith({
status: 200,
response: [{
customer_info_customers: ['', '', '', '', ''],
domain_info_customers: {},
}],
});
request.responseURL = 'banaan';
promise.then(() => {
// The contents were replaced, so it's best to forget whatever our selection was.
expect(component.currently_selected_list_value).toEqual(-1);
done();
});
});
});

Related

Calling a custom action from power apps component

I am trying to create a component that makes a post request to a custom action in my environment. This action has an input called leadid and an output called data, and when called triggers a custom plugin. However, I am having trouble trying to figure out how to call this action from my component.
I understand that you can make calls using this._context.webAPI.retrieveMultipleRecords(entity, query) but I am not trying to achieve this.
I have tried the following directly in the console (in the browser) and it works perfectly, but I get an error Xrm is not defined when using the same code in my TypeScript file:
fetch(Xrm.Page.context.getClientUrl() + "/api/data/v9.2/dev_GetData", {
"method":"POST",
"headers":{
"Accept": "application/json",
"Content-Type": "application/json; charset=utf-8",
"OData-MaxVersion": "4.0",
"OData-Version": "4.0"
},
"body": JSON.stringify({
"leadid": "7ba18ae0-4d0e-ea11-a813-000d3a1bbd52"
})
}).then((response) => response.json())
.then((data) => {
console.log(data);
})
I find this odd as when I hover over the other parts (page, context, getClientUrl), it gives me the details of what It does.
What might I be doing wrong, or how may I get the client url without using Xrm.page...?
There is Managed solution/Additional Tool for Dataverse which will give you code snippet with actual values for webapi call.
Tool is Dataverse Rest Builder
https://www.xrmtoolbox.com/plugins/GuidoPreite.DRB/
Example code snippet for Lead qualification Action
var execute_QualifyLead_Request = {
// Parameters
entity: { entityType: "lead", id: "524a9e0b-f3e6-e711-80e9-005056936c69" }, // entity
CreateAccount: true, // Edm.Boolean
CreateContact: true, // Edm.Boolean
CreateOpportunity: true, // Edm.Boolean
Status: 1, // Edm.Int32
getMetadata: function () {
return {
boundParameter: "entity",
parameterTypes: {
entity: { typeName: "mscrm.lead", structuralProperty: 5 },
CreateAccount: { typeName: "Edm.Boolean", structuralProperty: 1 },
CreateContact: { typeName: "Edm.Boolean", structuralProperty: 1 },
CreateOpportunity: { typeName: "Edm.Boolean", structuralProperty: 1 },
Status: { typeName: "Edm.Int32", structuralProperty: 1 }
},
operationType: 0, operationName: "QualifyLead"
};
}
};
Xrm.WebApi.online.execute(execute_QualifyLead_Request).then(
function success(response) {
if (response.ok) { return response.json(); }
}
).then(function (responseBody) {
var result = responseBody;
console.log(result);
// Return Type: Collection(mscrm.crmbaseentity)
}).catch(function (error) {
console.log(error.message);
});
[1]: https://github.com/GuidoPreite/DRB

Wordpress blocks: async REST calls in registerBlockType edit function

I'm writing a WordPress plugin that creates a block, the block needs to pull data using a custom REST endpoint that returns, in the example below, a simple string. I'd like to include this string in the return from edit() and save() in my registerBlockType config but. I'm using fetch() to call the REST endpoint but this, obviously, is async. Any thoughts on the best way to do this appreciated, thanks:
const { registerBlockType } = wp.blocks
registerBlockType( 'daisy-views/da-test', {
title: 'Daisy Test: Test Block',
icon: 'format-gallery',
category: 'common',
attributes: {
gid: {
default: 2,
type: 'integer'
},
},
edit( props ) {
const restEP = daRestUrl + 'test'
fetch( restEP, {
body: JSON.stringify( {p: 'test param'}), // test parameters
cache: 'no-cache',
method: 'POST',
redirect: 'follow',
referrer: 'no-referrer',
headers : {
'Access-Control-Allow-Origin' : '*',
'X-WP-Nonce' : wpApiSettings.nonce,
}
})
.then( response => {
response.json()
.then( data => {
var returnValue = data.data // REST test, returns a string
console.log( 'Fetch returns: ', returnValue )
})
})
return <div>
test block edit
{/* return value from fetch here */}
</div>
},
save( props ) {
return <div>
Test Block
{/* return value from fetch here */}
</div>
}
} );
My best solution, to date, is to add a code attribute and have the fetch call fill that attribute with HTML. if fetch is called directly in the edit function there needs to be a check to prevent it from being called in an endless loop when it updates the attribute.

Empty value on Polymer computed attribute

I am trying to use computed attribute in Polymer but I always get an empty value. In this case I have an attribute in my custom element called datagraph. And I make a post request to a server, get a JSON file, calculate the result and then show it. This is my custom element:
<dom-module id="cost-card">
<template>
<style>
p.datos3{
color: #10cebc;
text-align: center;
font-size: 22px;
margin-top: 0px;
}
</style>
<p class="datos3">{{datagraph}}</p>
</template>
<script>
Polymer({
is: "cost-card",
properties:{
usr:{
type: Number,
value: 2
},
command:{
type: String,
value: "SP_GetCostoCampania"
},
datagraph:{
type: Number,
computed: 'getCost(command,usr)'
}
},
getCost: function(command,usr){
var options = {
hostname: 'localhost',
path: '/',
port: 8081,
secure: false,
method: 'POST',
headers: {
'x-powered-by': 'HTTPClient.js'
},
'Content-Type': 'application/json'
}
var innerCost;
var example1 = new HTTPClient(options);
example1.post("/executeGraph1?command="+ command + "&param1=" + usr, function (err, res, body) {
body = JSON.parse(body);
innerCost = body[0].price * body[0].exchengeRate;
});
return innerCost;
}
});
</script>
</dom-module>
I have an express server running, information is being delivered correctly but the {{datagraph}} tag keeps empty. I think it may be because the post request is an anychronous task, and the value is being delivered later but I have also tried using Promise with the same result.
Does anyone know the proper way to do this?
As you've hinted, getCost is always going to return undefined because return innerCost is going to execute before the post's callback.
Computed properties are meant to take in other properties as arguments and are designed to be synchronous. If getCost took in some argument, even then you would want to use an observer that directly sets this.datagraph within the callback.
Since you aren't feeding any arguments into getCost, I would suggest you instead use a ready callback that makes the post request and sets this.datagraph within the callback.
For example:
Polymer( {
is: "cost-card",
properties: {
usr: { type: Number, value: 2 },
command: { type: String, value: "SP_GetCostoCampania" },
datagraph: Number
},
observers: [ "getCosto(command, usr)" ],
getCosto: function ( command, usr ) {
var options = {
hostname: "localhost",
path: "/",
port: 8081,
secure: false,
method: "POST",
headers: { "x-powered-by": "HTTPClient.js" },
"Content-Type": "application/json"
};
const uri = `/executeGraph1?command=${command}&param1=${usr}`;
new HTTPClient( options ).post( uri, ( err, res, body ) => {
// values have changed, ignore result (ideally cancel the HTTP request)
if ( command !== this.command || usr !== this.usr ) return;
body = JSON.parse( body );
this.datagraph = body[ 0 ].price * body[ 0 ].exchengeRate;
} );
}
} );

AngularJS: Unexpected undefined in chained results

I've come across this issue before with nested directives, but I managed to find a workaround there. I have code that looks a bit like,
var token = API.callGeneric({}, {method: 'kds.getTokenExtended2', params: ['demo', 'demo', '', '', '', '', '', false, '', '']}); //kds.
token.$promise
.then(function (result) {
if (!angular.isUndefined(result.error)) { // API error
$scope.msg = {iconClass: 'glyphicon-exclamation-sign', txt: 'Looks like there was a problem.'}
if (!APIErr.handle(result.error)) { // handle also returns continueExec flags
return;
}
}
$scope.msg = {iconClass: 'glyphicon-cloud-download', txt: 'almost there…'};
$scope.token = result.result;
console.log('result', result.result);
}, function (error) { // server error
$scope.msg = {iconClass: 'glyphicon-exclamation-sign', txt: 'issues with server, summoning the gods'}
APIErr.handle(error);
})
.then(function (result) {
$scope.msg = {}; // clear the message
// another api call to get bills
return API.callGeneric({}, {method: 'kds.getKitchenDisplayReceipts', params: [$scope.token, new Date().getTime()]});
}, APIErr.handle)
.then(function (result) {
console.log(result); // can see result.result.openReceipts
var receiptIds = result.result.openReceipts; // undefined?
}, APIErr.handle);
And API is a service that calls the API, obviously.
The problem is the last few lines, where console.log(result) shows result.result.openReceipts, and obviously result is a Resource object.
I'm stumped about what might be going on here. Any clues? How can I avoid this in future?
If you want to nest promises you need to return a promise every time.
Your second then is unnecessary in my opinion and could be done inside the first one as the first one is not returning any promises.
So it could be something like:
Pseudo-code:
API.call('token').then(function(result) {
...
return API.call('displayreceipts');
})
.then(function(result){
var recieptIds = result.result.openReceipts;
})
Let me know if it works.

REST API testing using vows, tobi and node.js

I am trying to combine the examples here, here to write a vows test for my node.js / express app that:
Creates a new user object
Checks the response was sane
Uses the returned _id to test looking up the newly created user
Again uses the _id to test updating the user
Item 1 and 2 work fine, but there is something wrong with my sub-context 'GET /users/:id'. It errors and I cannot figure out why. Tried Googling and using the debugger, but I still can't see what it is, I am probably just overlooking something obvious.
···✗ Errored » 3 honored ∙ 1 errored
Can anyone tell me why the 4th vow errors?
Here's my vows code:
var vows = require('vows')
, assert = require('assert')
, tobi = require('tobi')
var suite = vows.describe('Users API')
, now = new Date().getTime()
, newUser = { name: now + '_test_user', email: now + '#test.com' }
, browser = tobi.createBrowser(3000, 'localhost')
, defaultHeaders = { 'Content-Type': 'application/json' }
function assertStatus(code) {
return function (res, $) {
res.should.have.status(code)
}
}
var client = {
get: function(path) {
return function() {
browser.get(path, { headers: defaultHeaders }, this.callback)
}
},
post: function(path, data) {
return function() {
browser.post(path, { body: JSON.stringify(data), headers: defaultHeaders }, this.callback)
}
}
}
suite.addBatch({
'GET /users': {
topic: client.get('/users'),
'should respond with a 200 ok': assertStatus(200)
},
'POST /users': {
topic: client.post('/users', newUser),
'should respond with a 200 ok': assertStatus(200),
'should return the new user': function(res, $){
assert.isNotNull(res.body._id)
assert.isNotNull(res.body.created_at)
assert.isTrue(res.body._id.length > 0)
assert.equal(newUser.name, res.body.name)
assert.equal(newUser.email, res.body.email)
},
'GET /users/:id': { // Sub-context of POST /users
topic: function(res) { return client.get('/users/' + res.body._id) },
'should respond with a 200 ok': assertStatus(200)
}
}
})
suite.export(module)
EDIT
I tried simplifying the code as follows to help see if this.callback was the problem, but the error is still there:
'GET /users/:id': { // Sub-context of POST /users
topic: function(res) {
console.log('About to request /users/' + res.body._id)
browser.get('/users/' + res.body._id, { headers: defaultHeaders }, this.callback)
},
'should respond with a 200 ok': assertStatus(200)
}
How are you populating res for the fourth tes?? It wouldn't be visible outside the line
'should return the new user'
Try creating the id variable outside the addBatch call, and set it in the third test. then call
client.get('/users/' + id)
EDIT:
Better yet, put it back into newUser in the third test:
'should return the new user': function(res, $){
newUser.id = res.body._id
....
and then do:
client.get('/users/' + newUser.id)

Categories