I tried to test an action creator that returns a promise, using also redux mock store.
import promiseMiddleware from 'redux-promise-middleware';
import nock from 'nock';
import configureStore from 'redux-mock-store';
import { domain, port } from '../../config/environment';
import { GET_ITEMS_START,
GET_ITEMS_SUCCESS } from '../../constants/items';
import { getItems } from './items';
const promise = promiseMiddleware({
promiseTypeSuffixes: ['START', 'SUCCESS', 'ERROR']
});
describe('Get Items', () => {
it('should create GET_ITEMS_SUCCESS action after successfully getting items', (done) => {
nock(`${domain}:${port}`)
.get('/api/items')
.reply(200, {
_id: '1',
text: 'Make Eggs',
completed: false
});
const expectedActions = [
{ type: GET_ITEMS_START },
{ type: GET_ITEMS_SUCCESS, payload: {
data: { _id: '1', text: 'Make Eggs', completed: false }
}}
];
const store = mockStore({}, expectedActions, done);
store.dispatch(getItems());
});
});
and here is my action creator code
export function getItems() {
return {
type: GET_ITEMS,
payload: {
promise: axios.get(`${domain}:${port}/api/items`)
}
};
}
but the result is mismatch because the promise resolved a deep nested objects
Error: Expected { payload: { config: { headers: {}, method: 'get', timeout: 0, transformRequest: [ [Function] ], transformResponse: [ [Function] ], url: 'http://localhost:3000/api/items', withCredentials: undefined }, data: { _id: '1', completed: false, text: 'Make Eggs' }, headers: {}, status: 200, statusText: 'OK' }, type: 'GET_ITEMS_SUCCESS' } to equal { payload: { data: { _id: '1', completed: false, text: 'Make Eggs' } }, type: 'GET_ITEMS_SUCCESS' }
+ expected - actual
{
"payload": {
- "config": {
- "headers": {}
- "method": "get"
- "timeout": 0
- "transformRequest": [
- [Function]
- ]
- "transformResponse": [
- [Function]
- ]
- "url": "http://localhost:3000/api/items"
- "withCredentials": [undefined]
- }
"data": {
"_id": "1"
"completed": false
"text": "Make Eggs"
}
- "headers": {}
- "status": 200
- "statusText": "OK"
}
"type": "GET_ITEMS_SUCCESS"
}
I obviously don't want to copy all of those deep nested properties into my test suite.
Is there a better way of doing this?
If you're writing a unit test, you probably don't need to call the actual REST API. Instead you can mock axios and make it return some fake data which won't be so deep.
Related
I have a node API Gateway stack and a Node Lambda. I've been trying to get API gateway to return content-type: application/xml OR application/json depending on the request (returnType=xml or returnType=json).
I have tried adding response models and that didn't work. BinaryTypes didn't work either. I have gotten it to do either application/json OR application/xml but I can't get it to do both. Is what I'm trying to do even possible? or should I create two separate endpoints?
This example always returns application/json.
Here is my lambda:
exports.handler = async function (event, context, callback) {
var format = event.format;
if (!format) {
callback(Error("[BadRequest] missing parameters"));
}
const promise = new Promise(function (resolve, reject) {
https
.get("exampleendpoint.com", (res) => {
let body = "";
res.on("data", (chunk) => {
body += chunk;
});
res.on("end", () => {
var results = JSON.parse(body);
if (format && format.toUpperCase() === "XML") {
var response = {
statusCode: 200,
headers: { "content-type": "application/xml" },
body:
'<?xml version="1.0" encoding="UTF-8"?><result>' +
OBJtoXML(results) +
"</result>",
};
resolve(response);
} else {
var response = {
statusCode: 200,
headers: { "content-type": "application/json" },
body: JSON.stringify(results),
};
resolve(response);
}
});
})
.on("error", (e) => {
var response = {
statusCode: 500,
body: "",
errorMessage: "Error from example.com",
};
resolve(response);
});
});
return promise;
};
Here is my api gateway code:
const epqApi = new gateway.RestApi(this, "restApi", {
restApiName: "resultsApi",
cloudWatchRole: true,
description: "Calls the service for the app",
endpointTypes: [gateway.EndpointType.REGIONAL],
deployOptions: {
stageName: "prod",
loggingLevel: gateway.MethodLoggingLevel.OFF,
dataTraceEnabled: false,
},
});
const epqResource = epqApi.root.addResource("v1");
const epqIntegration: gateway.LambdaIntegration =
new gateway.LambdaIntegration(generatePqsResultFunction, {
proxy: false,
allowTestInvoke: true,
passthroughBehavior: gateway.PassthroughBehavior.NEVER,
contentHandling: gateway.ContentHandling.CONVERT_TO_TEXT,
requestTemplates: {
"application/json": `{
"format":"$input.params(\'format\')"
}`,
},
integrationResponses: [
{
statusCode: "200",
responseParameters: {
"method.response.header.Access-Control-Allow-Origin": "'*'",
},
responseTemplates: {
"application/json": "$input.path('$.body')",
"application/xml": "$input.path('$.body')",
},
},
{
statusCode: "400",
selectionPattern: "^\\[BadRequest\\].*",
responseParameters: {
"method.response.header.Access-Control-Allow-Origin": "'*'",
},
responseTemplates: {
"application/javascript":
"#set($inputRoot = $input.path('$')) {\"errorMessage\" : \"$input.path('$.errorMessage')\"}",
},
},
],
});
epqResource.addMethod("GET", epqIntegration, {
requestParameters: {
//all params need to be in here, even if they are not required
"method.request.querystring.x": false,
"method.request.querystring.y": false,
"method.request.querystring.units": false,
"method.request.querystring.format": false,
"method.request.querystring.wkid": false,
"method.request.querystring.includeDate": false,
},
methodResponses: [
// Successful response from the integration
{
statusCode: "200",
responseParameters: {
"method.response.header.Access-Control-Allow-Origin": true,
},
},
{
statusCode: "400",
responseParameters: {
"method.response.header.Access-Control-Allow-Origin": true,
},
},
],
});
}
I have Application model with following relation:
#belongsTo(() => Ido)
idoId: string;
export interface ApplicationRelations {
ido?: IdoWithRelations;
}
export type ApplicationWithRelations = Application & ApplicationRelations;
Application repository looks like this:
export class ApplicationRepository extends DefaultCrudRepository<
Application,
typeof Application.prototype.id,
ApplicationRelations
> {
public readonly user: BelongsToAccessor<
User,
typeof Application.prototype.id
>;
constructor(
#inject('datasources.db') dataSource: DbDataSource,
#repository.getter('UserRepository')
protected userRepositoryGetter: Getter<UserRepository>,
) {
super(Application, dataSource);
this.user = this.createBelongsToAccessorFor('user', userRepositoryGetter);
this.inclusionResolvers.delete('ido');
}
}
And the following relation in IDO model:
#hasMany(() => Application)
applications: Application[];
In post /ido in swagger i am getting this example for creating:
{
"applications": [
{
"status": "string",
"createdAt": 0,
"idoId": "string",
"userId": "string",
"ido": {
"applications": [
{
"status": "string",
"createdAt": 0,
"idoId": "string",
"userId": "string",
"ido": {
"applications": [
"string"
],
}
Is there any ways to remove the duplicate and kind of curricular relation for ido in application from swagger? Or this doesn't really matter and i can just manually delete all fields above the first application?
This answer was copied over from https://github.com/loopbackio/loopback-next/discussions/8536#discussioncomment-2655375.
OpenAPI/Swagger is at the REST layer, which means you'll need to look inside the respective REST Controller, which would have something similar to this:
#post('...')
function create(
#requestBody({
content: {
'application/json': {
schema: getModelSchemaRef(Application, {
title: 'NewApplication',
exclude: ['id'],
}),
},
},
})
)
You can modify it as such to exclude relations:
#post('...')
function create(
#requestBody({
content: {
'application/json': {
schema: getModelSchemaRef(Application, {
title: 'NewApplication',
exclude: ['id'],
+ includeRelations: false,
}),
},
},
})
)
An alternative is to use exclude.
More info can be found in the API docs: https://loopback.io/doc/en/lb4/apidocs.repository-json-schema.getjsonschemaref.html
After running npm run build, I get an error: Error: [VuetifyLoaderPlugin Error] No matching rule for vue-loader found.Make sure there is at least one root-level rule that uses vue-loader and VuetifyLoaderPlugin is applied after VueLoaderPlugin.
package.json
{
"name": "client",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate"
},
"dependencies": {
"#nuxtjs/axios": "^5.13.6",
"core-js": "^3.15.1",
"dotenv": "^10.0.0",
"nuxt": "^2.15.7",
"nuxt-i18n": "^6.27.3",
"nuxt-mail": "^3.0.10",
"vuetify": "^2.5.5"
},
"devDependencies": {
"#fortawesome/fontawesome-free": "^5.15.3",
"#fortawesome/fontawesome-svg-core": "^1.2.35",
"#fortawesome/free-brands-svg-icons": "^5.15.3",
"#fortawesome/free-solid-svg-icons": "^5.15.3",
"#fortawesome/vue-fontawesome": "^2.0.2",
"#mdi/font": "^5.9.55",
"#nuxtjs/fontawesome": "^1.1.2",
"#nuxtjs/vuetify": "^1.12.1",
"eslint-config-prettier": "^8.3.0",
"font-awesome": "^4.7.0",
"material-design-icons-iconfont": "^6.1.0",
"prettier": "^2.3.2"
}
}
Here is my config nuxt.config.js file:
import colors from 'vuetify/es5/util/colors'
import i18n from './config/i18n'
export default {
// Global page headers: https://go.nuxtjs.dev/config-head
head: {
titleTemplate: '%s - client',
title: 'client',
htmlAttrs: {
lang: 'en'
},
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: '' },
{ name: 'format-detection', content: 'telephone=no' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
// Global CSS: https://go.nuxtjs.dev/config-css
css: [
],
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [
],
// Auto import components: https://go.nuxtjs.dev/config-components
components: true,
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
buildModules: [
[
'nuxt-i18n',
{
vueI18nLoader: true,
defaultLocale: 'hr',
locales: [
{
code: 'en',
name: 'Eng'
},
{
code: 'hr',
name: 'Hrv'
}
],
vueI18n: i18n
}
],
'#nuxtjs/vuetify',
'#nuxtjs/fontawesome'
],
fontawesome: {
icons: {
solid: true,
brands: true
}
},
// Modules: https://go.nuxtjs.dev/config-modules
modules: [
// https://go.nuxtjs.dev/axios
'#nuxtjs/axios',
'#nuxtjs/vuetify',
'nuxt-i18n',
['nuxt-mail', {
message: {
to: 'mislav0508#hotmail.com',
},
smtp: {
host: "smtp-mail.outlook.com",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: "mislav0508#hotmail.com",
pass: process.env.EMAIL_PASS,
},
tls: {
rejectUnauthorized:false
}
},
}],
],
// Axios module configuration: https://go.nuxtjs.dev/config-axios
axios: {},
i18n: {
i18n: {
locales: ['hr', 'en'],
defaultLocale: 'hr',
vueI18n: {
fallbackLocale: 'hr',
messages: {
hr: {
welcome: 'Dobrodošli'
},
en: {
welcome: 'Welcome'
}
}
}
}
},
// Vuetify module configuration: https://go.nuxtjs.dev/config-vuetify
vuetify: {
customVariables: ['~/assets/variables.scss'],
theme: {
dark: false,
themes: {
dark: {
primary: colors.blue.darken2,
accent: colors.grey.darken3,
secondary: colors.amber.darken3,
info: colors.teal.lighten1,
warning: colors.amber.base,
error: colors.deepOrange.accent4,
success: colors.green.accent3
}
}
}
},
// Build Configuration: https://go.nuxtjs.dev/config-build
build: {
}
}
I've tried installing vuetify-loader and vue-loader and adding them to the nuxt.config.js file. However after that I get another error:
TypeError: loaderContext.emitError is not a function
Please help.
I have the following code:
Addresses.getorderHistory = function(address, baseToken, status, length, cb) {
console.log("lenght here -> " + length);
addressService.getorderHistory(address, baseToken, status, length, cb)
.catch(err => cb(err));
};
Addresses.remoteMethod('getorderHistory', {
http: { verb: 'get', path: '/:address/orderHistory' },
accepts: [
{ arg: "address", type: "string", required: true },
{ arg: "base_token", type: "string", required: true, 'http': {source: 'query'} },
{ arg: "status", type: "string", required: true, 'http': {source: 'query'} },
{ arg: "length", type: "string", required: true, 'http': {source: 'query'} }
],
returns: { type: 'object', root: true }
});
When I make a request like this
curl http://localhost:3001/<my root>/addresses/<my address>/orderHistory?base_token=<my token>&status=filled&length=100
It says
Error: status is a required argument
I can basically read address and baseToken values but I can't read status and length. What am I missing?
I am using Sencha V2. I am trying to populate my list with the values in a Users.json file.
The code in my list file is
Ext.define('iPolis.view.personlist',{
extend:'Ext.List',
xtype: 'personlist',
requires: [
'Ext.List',
'Ext.form.FieldSet',
'Ext.Button'
],
config: {
fullscreen:true,
items: [
{
xtype:'toolbar',
docked:'top',
title:'iPolis',
items:[
{
ui:'back',
icon:'home',
iconCls:'home',
iconMask:true,
id: 'homebtn',
handler:function ()
{
}
},
]
},
{
xtype : 'list',
store : 'personListStore',
itemTpl : '<div class="contact">HI <br/> {name}</div>'
}
}
]
}
});
and the store is calling the file using:
Ext.define('iPolis.store.personListStore', {
extend: 'Ext.data.Store',
storeId:'personListStore',
model : 'iPolis.model.personListModel',
proxy : {
type : 'ajax',
url : '/users.json',
reader: {
type: 'json',
rootProperty: 'users'
}
},
autoLoad: true
});
The code for my json file is:
{
"users": [
{
"id": 1,
"name": "Ed Spencer",
"email": "ed#sencha.com"
},
{
"id": 2,
"name": "Abe Elias",
"email": "abe#sencha.com"
}
]
}
I am gettin a blank screen. I have tried everything but no data is displayed on the screen.
In your list the store is personStore but your trying to use personListStore.
Ext.define('iPolis.store.personListStore', {
extend: 'Ext.data.Store',
config:{
model : 'iPolis.model.personListModel',
storeId:'personListStore',
proxy : {
type : 'ajax',
url : '/users.json',
reader: {
type: 'json',
rootProperty: 'users'
}
},
autoLoad: true } });
try this may help you.