Ember errors.add inside catch after save causes form button to not respond - express

My server responds with a 400 status if a book title already exists. The ember app catches the error and does a errors.add with the attribute name and error detail. For some reason when a receive the 400 when I change the title the form submit button is dead. I found that when I eliminate the errors.add line the problem goes away.
Here is my action:
import Ember from 'ember';
import DS from 'ember-data';
export default Ember.Route.extend({
model() {
return this.store.createRecord('book');
},
setupController: function(controller, model) {
controller.set('book', model);
controller.set('errors', DS.Errors.create());
},
actions: {
createBook: function(book) {
var _this = this;
var errors = _this.controllerFor('books.new').get('errors');
book.save().then(function(book) {
_this.transitionTo('books.book', book);
}).catch(function(response) {
response.errors.forEach(function(error) {
var attribute = error.source.pointer.split('/')[3];
//This line causes the problem---> errors.add(attribute, error.detail);
});
});
}
}
});
This is the response:
res.status(400).send({
errors: [
{
status: "400",
source: { pointer: '/data/attributes/title' },
title: "Invalid Attribute",
detail: 'must be unique'
}
]
});

Related

Vercel: This Serverless Function (FUNCTION_INVOCATION_FAILED)

I have an error that appears when I try to access my link
This Serverless Function has crashed.
Your connection is working correctly.
Vercel is working correctly.
500: INTERNAL_SERVER_ERROR
Code: FUNCTION_INVOCATION_FAILED
ID: cdg1:cdg1::bgdnz-1676557396498-149041f4043b
[GET] /6OzxT
15:07:51:26
2023-02-16T14:07:51.324Z 020abb04-a238-441a-8a1d-5a4fb96d66c3 ERROR Unhandled Promise Rejection {"errorType":"Runtime.UnhandledPromiseRejection","errorMessage":"TypeError: fetch failed","reason":{"errorType":"TypeError","errorMessage":"fetch failed","cause":{"errorType":"ConnectTimeoutError","errorMessage":"Connect Timeout Error","code":"UND_ERR_CONNECT_TIMEOUT","name":"ConnectTimeoutError","message":"Connect Timeout Error","stack":["ConnectTimeoutError: Connect Timeout Error"," at onConnectTimeout (/var/task/vercel/path0/node_modules/undici/lib/core/connect.js:182:24)"," at /var/task/vercel/path0/node_modules/undici/lib/core/connect.js:129:46"," at Immediate._onImmediate (/var/task/vercel/path0/node_modules/undici/lib/core/connect.js:170:9)"," at process.processImmediate (node:internal/timers:471:21)"]},"stack":["TypeError: fetch failed"," at fetch (/var/task/vercel/path0/node_modules/undici/index.js:113:13)"," at process.processTicksAndRejections (node:internal/process/task_queues:95:5)"]},"promise":{},"stack":["Runtime.UnhandledPromiseRejection: TypeError: fetch failed"," at process.<anonymous> (file:///var/runtime/index.mjs:1194:17)"," at process.emit (node:events:525:35)"," at emit (node:internal/process/promises:149:20)"," at processPromiseRejections (node:internal/process/promises:283:27)"," at process.processTicksAndRejections (node:internal/process/task_queues:96:32)"]}
Unknown application error occurred
Runtime.Unknown
I tried to add a try/catch, and normally it should be redirected to the URL (here steellgold.fr)
+page.server.ts (Redirect page) (https://preview.linkfy.fr/6OzxT)
import { PUBLIC_URL, PUBLIC_API_URL } from "$env/static/public";
import type { Link } from "$lib/types/link.type";
import { restRequest } from "$lib/utils/request/request";
import { error, redirect } from "#sveltejs/kit";
import type { PageServerLoad } from "./$types";
// eslint-disable-next-line
export const load = (async({ params }) => {
if (!params.slug) throw redirect(303, PUBLIC_URL);
const data = await restRequest<Link>("get", PUBLIC_URL + "api/link", {
query: {
slug: params.slug
}
}, [], true);
if (!data.success) {
throw error(404, { message: "This link not exist or has been disabled", code: 404 });
}
try {
fetch(PUBLIC_API_URL + "link/" + params.slug);
} catch (e) {
console.error(e);
}
if (!data.data.status) throw error(423, { message: "This link has been disabled", code: 423 });
throw redirect(303, data.data.url);
}) satisfies PageServerLoad;
increment.ts (Fastify route fort increment links)
import { FastifyReply, FastifyRequest } from "fastify";
import { app } from "../..";
import { Link } from "../../types/link";
import { error, success, warn } from "../../utils/logger";
import prisma from "../../utils/prisma";
app.get("/link/:slug", {
handler: async(request: FastifyRequest<{ Params: Link }>, reply: FastifyReply) => {
reply.status(200).send({ message: "Correctly routed received request." });
warn(`[GET] incrementing link with slug /${request.params.slug}.`);
const link = await prisma.link.findUnique({
where: { slug: request.params.slug }
});
if (!link) {
reply.status(404).send({ error: "Link not found" });
error(`[404] Link with slug /${request.params.slug} not found.`);
return;
}
await prisma.link.update({
where: { slug: request.params.slug },
data: { clicks: link.clicks + 1 }
});
success(`[200] Link with slug /${request.params.slug} incremented by 1.`);
return reply.status(200).send({
message: "Link incremented successfully."
});
}
});```
All codes is open-source: https://github.com/Steellgold/Linkfy or https://github.com/Steellgold/LinkfyAPI if you want

How to access Vue component data inside callback

Im trying to integrate Paymentez (a payments processor) into my site. I get "success" or "failure" responses after doing a test transaction but cant change data in the Vue component (want to show a modal/dialog).
data: function() {
return {
success: false,
failure: false
}
},
created() {
this.paymentCheckout = new window._PAYMENTEZ.modal({
client_app_code: "***********", // Client Credentials
client_app_key: "***************", // Client Credentials
locale: "es", // User's preferred language (es, en, pt). English will be used by default.
env_mode: "stg", // `prod`, `stg`, `local` to change environment. Default is `stg`
onOpen: function () {
console.log("modal open");
},
onClose: function () {
console.log("modal closed");
},
onResponse: function (response) {
// The callback to invoke when the Checkout process is completed
/*
In Case of an error, this will be the response.
response = {
"error": {
"type": "Server Error",
"help": "Try Again Later",
"description": "Sorry, there was a problem loading Checkout."
}
}
When the User completes all the Flow in the Checkout, this will be the response.
response = {
"transaction":{
"status": "success", // success or failure
"id": "CB-81011", // transaction_id
"status_detail": 3 // for the status detail please refer to: https://paymentez.github.io/api-doc/#status-details
}
}*/
console.log(response);
document.getElementById("response").innerHTML = JSON.stringify(
response
);
},
});
/* what I want is something like:
if(response.transaction.status == "success") {
this.success = true
}
else if(response.transaction.status == "failure") {
this.failure = true
}
else if (response.error) {
// show error
}
*/
I've added the Paymentez library via CDN and initialized it in a created() hook.
this.success and this.failure remain false.
Cant access this inside the callback
To be able to access the outer this, your callbacks need to be arrow functions. Example:
// ...
onResponse: response => {
this.success = true; // <= works! (changes your component's reactive prop).
console.log('console is your friend', this);
console.log(response);
}
//...
If they're normal functions they overwrite the outer this with their own scope (and that's what this points to inside them). Read more here.

How to test an Error of a Method in a Vue.js Component using jest

How can I test the method createUser() of my Vue component? I want to test if the createUser() method throws an Error if the firstname < 2 for example. How is this possible?
I'm not really familiar with testing VUE components. It's my first time, so I have no idea how to get access the VUE component and how to submit for a example a username to the component
<script>
import {ApiService} from '../ApiService.js';
import {User} from '../User.js';
//const API_URL = 'http://localhost:8080';
const apiService = new ApiService();
export default {
name: "CreateUser",
data() {
return {
input: {
username: "",
firstname: "",
lastname: "",
title: "",
password: "",
groupId: "",
groups: [],
},
}
},
/.../
methods: {
getAllGroups() {
apiService.getAllGroups().then((data) => {
this.input.groups = data;
});
},
createUser() {
if (this.input.firstname == null || this.input.firstname.length < 2 || this.input.firstname > 50) {
throw ("Firstname to short/long/empty");
} else {
let user = new User(this.input.username, this.input.lastname, this.input.title, this.input.firstname, this.input.password, this.input.groupId)
apiService.createUser(user).then(() => {
location.reload()
});
}
},
I tried the following, but something doesn't not work
import { shallowMount } from '#vue/test-utils';
import UserModal from "../src/views/UserModal";
describe('UsarModal', () => {
it('should throw error when first name is too short', () => {
const myItems = [
{
username: "Heinz",
firstname: "H",
lasname: "Müller"}
]
const wrapper = shallowMount(UserModal, {
input: {
myItems
}
})
expect(wrapper.vm.createUser()).toThrow("Firstname to short/long/empty")
})
})
since in the code, it is throwing an error, so we will need to add a catch block in our test case to test this scenario. PFB example for your case:
try {
wrapper.vm.createUser();
} catch (error) {
expect(error).toBe('Firstname to short/long/empty');
}
let me know if you face any issue.
What you did in your example is very close. You just need to wrap the function call that is going to throw the exception in a lambda, e.g.
expect(() => wrapper.vm.createUser()).toThrow("Firstname to short/long/empty")
As described in the docs: https://jestjs.io/docs/expect#tothrowerror
It's probably doing something like internally wrapping the lambda in a try/catch, but I think using this method is a bit nicer than wrapping in a try/catch in your own test.
Thanks for the tip! But still something is not working right. It seems for me, that it does not accept my mock-data for input. I want to test if a got an error when I use a username which is too short. But even when I put a username that's long enough, the try catch block catches my error as you can see in the attached picture.
import {shallowMount} from '#vue/test-utils'
import UserModal from "./UserModal";
describe('ParentComponent', () => {
test("displays 'Emitted!' when custom event is emitted", () => {
const wrapper = shallowMount(UserModal, {
input: {
username: "asfsf",
firstname: "thomas",
lastname: "bird",
title: "Dr.",
password: "asdasda",
groupId: "2",
groups: [],}
});
try {
wrapper.vm.createUser();
} catch (error) {
expect(error).toBe("username missing");
}
})
});
Error Log

Realm "observer.next create #[native code]" exception

I am trying to fetch data with apollo and then write it to realm. I have created a js file that I know works, because it has worked before. But, when I try to write to a particular model I get an error message. More details as follows:
Code (Not entire code) LocationQuery.js:
const realm = new Realm({ schema: [testBuilding1], schemaVersion: 1 });
let buildingTypeArray = [];
const temp = [];
class LocationQuery extends Component {
static get propTypes() {
return {
data: React.PropTypes.shape({
loading: React.PropTypes.bool,
error: React.PropTypes.object,
sites: React.PropTypes.array,
}).isRequired,
};
}
render() {
if (this.props.data.loading) {
return (null);
}
if (this.props.data.error) {
return (<Text>An unexpected error occurred</Text>);
}
if (this.props.data.sites) {
this.props.data.sites.map((value) => {
buildingTypeArray.push(value.locations);
});
buildingTypeArray.forEach((locationValues) => {
realm.write(() => {
realm.create('testBuilding1', {
building: '273',
});
});
});
}
return null;
}
}
const locationQueryCall = gql`
query locationQueryCall($id: String!){
sites(id: $id){
locations {
building
type
}
}
}`;
const ViewWithData = graphql(locationQueryCall, {
options: props => ({
variables: {
id: 'SCH1',
},
}),
})(LocationQuery);
export default connect(mapStateToProp)(ViewWithData);
The error I get is a big red screen that read:
console.error: "Error in observe.next.... blah blah blah"
The Model I am using:
export const testBuilding1 = {
name: 'testBuilding1',
properties: {
building: 'string',
},
};
The weird thing is that the code works when I use this model:
export const locationScene = {
name: 'locationScene',
properties: {
building: 'string',
},
};
I am calling LocationQuery.js in another piece of code passing it through at render.
Thank you in advance for the help!

VueJS Promise is failing

I have a products component and a product owner component. Each Product will have an owner
What I am trying to do
I am receiving a list of products by calling an API endpoint. When the promise is resolved, I have a list of Products. Each Product has an OwnerID. I am trying to call another API Endpoint to fetch the name of the owner and assign it to the current product being iterated.
My Code so far
<script>
var config = require('../config');
export default {
data () {
return {
products: [],
}
},
ready () {
this.getProducts().then(t => {
console.log(t);
});
},
methods : {
getProducts : function() {
let url = config.API.GetProduct
this.$http.get(url).then(response=> {
this.products = response.data.resource;
var p = this.products.map(this.getOwner);
return Promise.all(p);
}, error=> {
console.error("An error happened!")
});
},
getOwner : function(product) {
let url = config.API.GetProductOwnerName.replace('[$$$]', product.OwnerID);
var p = new Promise();
this.$http.get(url).then(response => {
product.OwnerID = response.data.resource[0].OwnerName;
p.resolve(currentObj);
});
return p;
}
}
components: {}
}
</script>
Error that I am facing
Now whenever I am trying to do that, I keep getting the following errors
Uncaught TypeError: Cannot read property 'then' of undefined
Uncaught (in promise) TypeError: Promise resolver undefined is not a function(…)
Can somebody please let me know what I am doing wrong here ?
Thanks
You don't have to recreate a new promise object. You can just return the object you want to be passed to the next call.
getProducts: function() {
let url = config.API.GetProduct
return this.$http.get(url).then(response => {
this.products = response.data.resource;
return this.products.map(this.getOwner);
}, error=> {
console.error("An error happened!")
});
},