Ionic2 proxies not working with ionic run but working with ionic serve? - ionic2

For my ionic.config.json I have:
{
"name": "TSICMobile",
"app_id": "6e4680fa",
"typescript": true,
"v2": true,
"proxies": [
{
"path": "/api",
"proxyUrl": "http://192.168.0.105:8081/api"
}
]
}
In my provider (user-data.ts, based on Ionic2 conference app) I have for example:
login(credentials) {
return new Promise((resolve, reject) => {
this.http.post(
'/api/Login',
JSON.stringify(credentials),
{ headers: this.contentHeader }
).subscribe(res => {
console.log('api/Login return');
this.data = res.json();
if (this.data.authenticated === true) {
this.storage.set('TSIC_USER_PROFILE', JSON.stringify(this.data.tsiC_USER_PROFILE));
this.storage.set('TSIC_USER_ROLES', JSON.stringify(this.data.listRoles));
this.storage.set('tsic_id_token', this.data.token);
this.events.publish('user:login');
resolve(true);
} else {
reject('not authenticated');
}
}, error => {
console.log('api/Login failed');
reject(error);
});
});
}
when running:
ionic serve --lab -c
the proxy works perfectly and posts to http://192.168.0.105:8081/api/Login
when running
ionic run android -c
the post url is file://api/Login, and obviously fails.
Need assistance in understanding why (seemingly), the proxy is not in effect when running on device, and what I may be doing wrong or not understanding.

You don't need a proxy when you are on your device because ionic can handle the cors there. You need the proxy on serve because the browser is trying to handle the CORS and its more strict with it.
What I suggest you do is check if window.cordova exists and if it does use the normal url and otherwise the proxy url.
Like this:
login(credentials) {
return new Promise((resolve, reject) => {
this.http.post(
window.cordova?:'http://192.168.0.105:8081/api/Login':'/api/Login':,
JSON.stringify(credentials),
{ headers: this.contentHeader }
).subscribe(res => {
console.log('api/Login return');
this.data = res.json();
if (this.data.authenticated === true) {
this.storage.set('TSIC_USER_PROFILE', JSON.stringify(this.data.tsiC_USER_PROFILE));
this.storage.set('TSIC_USER_ROLES', JSON.stringify(this.data.listRoles));
this.storage.set('tsic_id_token', this.data.token);
this.events.publish('user:login');
resolve(true);
} else {
reject('not authenticated');
}
}, error => {
console.log('api/Login failed');
reject(error);
});
});
}

Short answer is the proxy is really only useful for ionic serve. For ionic run you need to use cordova-plugin-whitelist
https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-whitelist/
What this means for you though is, you'll have to swap your URIs during build. So instead of just /api/myAwesomeService you'll actually have http://192.168.0.105:8081/api as your URI when running on a real device.

this official article exactly shows you how to deal with this situation.
http://blog.ionic.io/handling-cors-issues-in-ionic/
an easier way is defining a Constant just like this:
.constant('SERVER', {
// when not using proxy
//url: 'https://myextsite.com/api/public/index.php/v1'
// when using proxy
url: 'v1'
})
ref: https://forum.ionicframework.com/t/solved-ionicview-app-http-request-to-external-api/18696/3

Related

What is the best way to mock ember services that use ember-ajax in ember-cli-storybook to post and fetch data?

I'm using Ember CLI Storybook to create a story of a component than internally relies upon services that communicate to the internet, to fetch and post information to the backend. The way I'm doing that is using ember-ajax.
I see how to mock an ember model from this section but wondering if there is a workaround for ember ajax service.
I like to use mswjs.io for mocking remote requests. It uses a service worker so you can still use your network log as if you still used your real API.
I have an example repo here showing how to set it up: https://github.com/NullVoxPopuli/ember-data-resources/
But I'll copy the code, in case I change something.
Now, in tests, you'd want something like this: https://github.com/NullVoxPopuli/ember-data-resources/blob/main/tests/unit/find-record-test.ts#L17
module('findRecord', function (hooks) {
setupMockData(hooks);
But since you're using storybook, you'd instead want the contents of that function. (And without the setup/teardown hooks unique to tests)
https://github.com/NullVoxPopuli/ember-data-resources/blob/main/tests/unit/-mock-data.ts#L22
import { rest, setupWorker } from 'msw';
let worker;
export async function setupMockData() {
if (!worker) {
worker = setupWorker();
await worker.start();
// artificial timeout "just in case" worker takes a bit to boot
await new Promise((resolve) => setTimeout(resolve, 1000));
worker.printHandlers();
}
let data = [
{ id: '1', type: 'blogs', attributes: { name: `name:1` } },
{ id: '2', type: 'blogs', attributes: { name: `name:2` } },
{ id: '3', type: 'blogs', attributes: { name: `name:3` } },
];
worker.use(
rest.get('/blogs', (req, res, ctx) => {
let id = req.url.searchParams.get('q[id]');
if (id) {
let record = data.find((datum) => datum.id === id);
return res(ctx.json({ data: record }));
}
return res(ctx.json({ data }));
}),
rest.get('/blogs/:id', (req, res, ctx) => {
let { id } = req.params;
let record = data.find((datum) => datum.id === id);
if (record) {
return res(ctx.json({ data: record }));
}
return res(
ctx.status(404),
ctx.json({ errors: [{ status: '404', detail: 'Blog not found' }] })
);
})
);
}
Docs for msw: https://mswjs.io/

Calling a Serenity service endpoint and react to success or failure on client-side

Until recently (one of the last full .net SF versions), I could call a Serenity service endpoint like below and react on success or failure. With current .net core (3.14.3) SF, somehow this seems not anymore to work.
I just get a dialog with the message content. I neither get "success" nor "error" alert box.
Question: How to do this with current SF 3.14.3.
Here my code from a project on full .net where this still works:
let bla1 = CountriesService.ImportCountriesFromRESTCountries(
{
},
response => {
alert('success');
let message = JSON.parse(bla1.responseText);
Q.notifySuccess(message, Q.text("Dialogs.Button.UpdateCountries.Import.Toast.Title"), options);
this.refresh();
},
{
blockUI: true,
onError: response => {
alert('error');
let errorcontent = JSON.parse(bla1.responseText);
let message = errorcontent["Error"]["Message"]
Q.alert(message);
this.refresh();
}
});
face same issue , i resolved this by
Q.serviceCall<Serenity.RetrieveResponse<any>>({
service: this.serviceUrl + '/Retrieve',
request: {
EntityId: this.value
} as Serenity.RetrieveRequest,
async: false,
onSuccess: (response) => {
this._selectedItem = response.Entity;
},
onError: (error) => {
console.log( error.Error);
}
});

testing multiple http request using mocha

I've been trying to solve this issue for days;
create the test for this case using mocha:
app.post('/approval', function(req, response){
request.post('https://git.ecommchannel.com/api/v4/users/' + req.body.content.id + '/' + req.body.content.state + '?private_token=blabla', function (error, resp, body) {
if (resp.statusCode == 201) {
//do something
} else {
response.send("failed"), response.end();
}
});
} else {
response.send("failed"), response.end();
}
});
});
I've tried several ways, using supertest to test the '/approval' and using nock to test the post request to git api. But it always turn "statusCode" is undefined. I think that's because the request to git api in index.js is not inside a certain function(?)
So I can't implement something like this :
https://codeburst.io/testing-mocking-http-requests-with-nock-480e3f164851 or
https://scotch.io/tutorials/nodejs-tests-mocking-http-requests
const nockingGit = () => {
nock('https://git.ecommchannel.com/api/v4/users')
.post('/1/yes', 'private_token=blabla')
.reply(201, { "statusCode": 201 });
};
it('approval', (done) => {
let req = {
content: {
id: 1,
state: 'yes'
},
_id: 1
}
request(_import.app)
.post('/approval')
.send(req)
.expect(200)
.expect('Content-Type', /html/)
.end(function (err, res) {
if (!err) {
nockingGit();
} else {
done(err);
}
});
done();
})
Then I tried to use supertest as promise
it('approve-block-using-promise', () => {
return promise(_import.app)
.post('/approval')
.send(req = {
content: {
id: 1,
state: 'yes'
},
_id: 1
})
.expect(200)
.then(function(res){
return promise(_import.app)
.post("https://git.ecommchannel.com/api/v4/users/")
.send('1/yes', 'private_token=blabla')
.expect(201);
})
})
But it gives error: ECONNEREFUSED: Connection refused. I didn't find any solution to solve the error. Some sources said that it needs done() .. but it gives another error message, 'ensure "done()" is called" >.<
So then I've found another way, using async (https://code-examples.net/en/q/141ce32)
it('should respond to only certain methods', function(done) {
async.series([
function(cb) { request(_import.app).post('/approval')
.send(req = {
content: {
id: 1,
state: 'yes'
},
_id: 1
})
.expect(200, cb); },
function(cb) { request(_import.app).post('/https://git.ecommchannel.com/api/v4/users/').send('1/yes', 'private_token=blabla').expect(201, cb); },
], done);
});
and it gives this error : expected 201 "Created", got 404 "Not Found". Well, if I open https://git.ecommchannel.com/api/v4/users/1/yes?private_token=blabla in the browser it does return 404. But what I expect is I've injected the response to 201 from the unit test; so whatever the actual response is, the statusCode suppose to be 201, right?
But then since it gives that error, is it means the unit test really send the request to the api?
Pls help me to solve this; how to test the first code I shared.
I really new into unit test.
There are a few things wrong with your posted code, I'll try to list them out but I'm also including a full, passing example below.
First off, your call to git.ecommchannel in the controller, it's a POST with no body. While this isn't causing the errors you're seeing and is technically not incorrect, it is odd. So you should double check what the data you should be sending is.
Next, I'm assuming this was a copy/paste issue when you created the question, but the callback for the request in your controller is not valid JS. The brackets don't match up and the send "failed" is there twice.
Your Nock setup had two issues. First the argument to nock should only have origin, none of the path. So /api/v4/users had to be moved into the first argument of the post method. The other issue was with the second argument passed to post that is an optional match of the POST body. As stated above, you aren't currently sending a body so Nock will always fail to match and replace that request. In the example below, the private_token has been moved to match against the query string of the request, as that what was shown as happening.
The calling of nockingGit was happening too late. Nock needs to register the mock before you use Supertest to call your Express app. You have it being called in the end method, by that time it's too late.
The test labeled approve-block-using-promise has an issue with the second call to the app. It's calling post via Supertest on the Express app, however, the first argument to that post method is the path of the request you're making to your app. It has nothing to do with the call to git.ecommchannel. So in that case your Express app should have returned a 404 Not Found.
const express = require('express')
const nock = require('nock')
const request = require('request')
const supertest = require('supertest')
const app = express()
app.use(express.json())
app.post('/approval', function(req, response) {
const url = 'https://git.ecommchannel.com/api/v4/users/' + req.body.content.id + '/' + req.body.content.state
request.post({
url,
qs: {private_token: 'blabla'}
// body: {} // no body?
},
function(error, resp, body) {
if (error) {
response.status(500).json({message: error.message})
} else if (resp.statusCode === 201) {
response.status(200).send("OK")
} else {
response.status(500).send("failed").end();
}
});
});
const nockingGit = () => {
nock('https://git.ecommchannel.com')
.post('/api/v4/users/1/yes')
.query({private_token: 'blabla'})
.reply(201, {"data": "hello world"});
};
it('approval', (done) => {
const reqPayload = {
content: {
id: 1,
state: 'yes'
},
_id: 1
}
nockingGit();
supertest(app)
.post('/approval')
.send(reqPayload)
.expect(200)
.expect('Content-Type', /html/)
.end(function(err) {
done(err);
})
})

Skype Web SDK stops updating presence

I am using Skype Web SDK with ionic.
I have two buttons in app after login like "Idle" and "Busy". When I click on it, its changing status of user on Skype for business o365 accordingly.
Now, When I run the app, After login, its work well for first one hour or so and then the app stops reflecting status on Skype For Business.
I get 404 - not found error once it stops updating status.
POST https://webpooldb41e02.infra.lync.com/ucwa/oauth/v1/applications/1145363530/me/reportMyActivity 404 (Not Found)
below is the code I am using for authentication,
let authContext = new Microsoft.ADAL.AuthenticationContext("https://login.windows.net/common");
authContext.acquireTokenSilentAsync("https://graph.windows.net", "Client_id")
.then(function(res) {
console.log(res);
cordova.plugins.backgroundMode.disableWebViewOptimizations();
Skype.initialize({
apiKey: 'Api Key'
}, function (api) {
console.log(new Date().toLocaleString()+" 2");
console.log(api.UIApplicationInstance);
//console.log(this.ucwaData);
window.skypeWebApp = "";
window.skypeWebApp = api.UIApplicationInstance;
window.skypeWebApp.signInManager.signIn({
"client_id": client_id,
"origins": ["https://webdir.online.lync.com/autodiscover/autodiscoverservice.svc/root"],
"cors": true,
"version": 'SkypeOnlinePreviewApp/1.0.0',
"redirect_uri": 'https://login.microsoftonline.com/common/oauth2/nativeclient'
}).then(function () {
console.log(new Date().toLocaleString()+" done");
});
}, function (err) {
console.log(new Date().toLocaleString()+" 3");
console.log(err);
});
}, function () {
cordova.plugins.backgroundMode.disableWebViewOptimizations();
// We require user credentials so triggers authentication dialog
authContext.acquireTokenAsync("https://graph.windows.net", "client_id", "https://login.microsoftonline.com/common/oauth2/nativeclient")
.then(function(res){
if (typeof(document.getElementById("login_with_office")) != 'undefined' && document.getElementById("login_with_office") != null)
{
document.getElementById("login_with_office").innerHTML = "Please wait … Connecting";
}
console.log(res);
//document.getElementById("login_with_office").setAttribute('disabled', 'disabled');
ctrl.loginwitho365();
}, function (err) {
console.log(new Date().toLocaleString()+" Failed to authenticate: " + err);
});
});
And Below is the code I am using for updating status,
window.skypeWebApp.signInManager.state.get().then(function (stat) {
if(stat == "SignedIn")
{
window.skypeWebApp.personsAndGroupsManager.mePerson.status.set(availability);
}
else
{
//Signin COde
}
});

PouchDB + Cloudant + Ionic2 - Works on browser, error on sim/device

I'm building an ionic2 app that uses local PouchDB and interacts with a Cloudant db. On the browser the app works fine, but on the iOS simulator, I get the following error.
ionic run ios -c and
safari console error
The code is as follows:
getHives() {
return new Promise(resolve => {
this.db.query('DesignDoc/ViewName', {
include_docs: true,
attachments: true,
key: this.loggedInUser
}).then(result => {
this.someList = [];
result.rows.map((row) => {
console.log("Row : " + JSON.stringify(row));
if (row.doc.type == "someCondition") {
this.someList.push(row);
}
});
resolve(this.someList);
this.db.changes({
live: true,
since: 'now',
include_docs: true,
attachments: true,
filter: '_view',
view: 'DesignDoc/ViewName',
key: this.loggedInUser
}).on('change', (change) => {
this.handleChange(change);
});
});
}).catch((error) => {
console.log("Error : " + error);
});
}
Can someone help me with what's going wrong here...also what's the _local/xyz...text after my cloudant URL ?
Thanks.