I'm experimenting with Monaco as an editor for a custom language.
I use this code to show an example error in the playground (some parts omitted):
const editor = monaco.editor.create(<omitted>);
const model = editor.getModel();
model.onDidChangeContent(event => {
const value = model.getValue();
const errors = GetErrors(value); // Implementation of GetErrors() not shown here
monaco.editor.setModelMarkers(model, "Example", errors);
});
Which results in the desired error in the editor:
How do I make a quick fix appear for that error? (Instead of "No quick fixes available")
I've looked at monaco.languages.registerCodeActionProvider() but I don't see how that ties in to the error detection code.
More generally, I've struggled to find examples for implementing Quick Fix with Monaco.
I got it working using a Code Action Provider.
The key was to use context.markers inside provideCodeActions() to get the errors I raised elsewhere (via setModelMarkers()).
monaco.languages.registerCodeActionProvider("myLanguage", {
provideCodeActions: (
model /**ITextModel*/,
range /**Range*/,
context /**CodeActionContext*/,
token /**CancellationToken*/
) => {
const actions = context.markers.map(error => {
return {
title: `Example quick fix`,
diagnostics: [error],
kind: "quickfix",
edit: {
edits: [
{
resource: model.uri,
edits: [
{
range: error,
text: "This text replaces the text with the error"
}
]
}
]
},
isPreferred: true
};
});
return {
actions: actions,
dispose: () => {}
}
}
});
Would still love to know if I'm missing an obvious source of documentation or examples for Monaco. I pieced this together using https://microsoft.github.io/monaco-editor/api/index.html and monaco.d.ts but it took a lot of trial and error.
Related
I've got the following code I transformed from a Trypescript, ESM-syntax based file to a Javascript, CJS-syntax file.
const apiClientFactory = require("#vue-storefront/core");
function onCreate(settings) {
return {
config: settings,
client: {},
};
}
const getPrice = () => {
console.log("$55,98")
}
const { createApiClient } = apiClientFactory({
onCreate,
api: {
getPrice,
},
});
module.exports = {
createApiClient,
};
I can not seem to find if the error "apiClientFactory is not a function" originates from old ESM-based code. Or that the function isn't called properly. However, apiClientFactory is correctly imported (ESM syntax)
What are you trying to achieve with this?
Because the whole Vue Storefront project uses TypeScript, so I recommend you to use it and follow the procedures and code standards that we are using.
To find a good example on the API please check the code for the integrations of Magento or Vendure.
i am just trying to learn JavaScript. I have to create a web application for school. Now i am trying to fetch data from a self written api. The backend is written with express, the frontend with JavaScript. I have got a overview page, where all products are shown. After clicking on the detail button, the user should be able to view the details of the selected product. For this i use this code.
import React, { useState, useEffect } from "react";
import "./Articles.css";
function ArticleDetail({ match }) {
useEffect(() => {
fetchArticle();
}, []);
const [article, setArticle] = useState([]);
async function fetchArticle() {
try {
const response = await fetch(
`http://localhost:8000/api/articles/${match.params.id}`
);
const article = await response.json();
//console.log(data.results);
console.log(article);
setArticle(article);
return article;
} catch (error) {
console.error(error);
}
}
return (
<div>
<p>TEST</p>
<p>{article.articles.pk_article_nr}</p>
<p>TEST</p>
</div>
);
}
export default ArticleDetail;
If i run this code and don't refresh the page by myself, the correct value (pk_article_nr) is shown. If i refresh the browser manually there is this error
TypeError: Cannot read properties of undefined (reading 'pk_article_nr')
This data are shown in the console:
{articles: {…}}
articles:
article_description: "lorem ipsum"
article_expiretimestamp: "2022-01-15 18:52:27"
article_picture: null
article_timestamp: "2022-01-15 18:37:27"
article_title: "Test 4"
bid_amount: 80
fk_article_nr: 4
fk_user_userid: null
pk_article_nr: 4
pk_bid_id: 8`
Could you please help me? I haven't found anything that helps me. Maybe i just searched for the wrong thing.
Thank you,
Max
You should change
<p>{article.articles.pk_article_nr}</p>
to
<p>{article?.articles?.pk_article_nr}</p>
Reason for this to happen:
React wants to access the property before mounting, while the property has not yet received any content
I'm using React Admin and ra-data-graphQl, when I update something in my UserEdit component all works perfect, BUT, when I need to handle the error message from the API, I don't know where catch it.
This is my Update query:
case 'UPDATE': {
const updateParams = { ...params };
return {
query: gql`mutation updateUser($id: ID!, $data: UpdateUser!) {
data: updateUser(id: $id,input:$data) {
${buildFieldsGraphQL(updateFields)}
}
}`,
variables: {
...updateParams,
id: updateParams.data.uuid,
data: {
...updateParams.data,
},
},
parseResponse: (response) => {
console.log('tr response: ', response);
},
};
}
When the API returns an error, it never reach the console.log.
I was searching a list with options here (https://github.com/marmelab/react-admin/tree/master/packages/ra-data-graphql#options) searching something like "parseError", but I did not find nothing similar.
I need to catch the error and show a message in the UserEdit form.
Reading the link that I share in this post, it say this:
but must return an object matching the options of the ApolloClient query method with an additional parseResponse function.
I understand that I should go to the link in the word "query" and check if there is something like "parserError", but the link is broken:
https://www.apollographql.com/docs/react/reference/index.html#ApolloClient.query
Any help?
Ok, its easier. By adding the onFailure function I can handle the error.
After putting off testing for a while now due to Cypress not allowing visiting chrome:// urls, I decided to finally understand how to unit/integration test my extension - TabMerger. This comes after the many times that I had to manually test the ever growing functionality and in some cases forgot to check a thing or two. Having automated testing will certainly speed up the process and help me be more at peace when adding new functionality.
To do this, I chose Jest since my extension was made with React (CRA). I also used React Testing Library (#testing-library/react) to render all React components for testing.
As I recently made TabMerger open source, the full testing script can be found here
Here is the test case that I want to focus on for this question:
import React from "react";
import { render, fireEvent } from "#testing-library/react";
import * as TabFunc from "../src/Tab/Tab_functions";
import Tab from "../src/Tab/Tab";
var init_groups = {
"group-0": {
color: "#d6ffe0",
created: "11/12/2020 # 22:13:24",
tabs: [
{
title:
"Stack Overflow - Where Developers Learn, Share, & Build Careersaaaaaaaaaaaaaaaaaaaaaa",
url: "https://stackoverflow.com/",
},
{
title: "lichess.org • Free Online Chess",
url: "https://lichess.org/",
},
{
title: "Chess.com - Play Chess Online - Free Games",
url: "https://www.chess.com/",
},
],
title: "Chess",
},
"group-1": {
color: "#c7eeff",
created: "11/12/2020 # 22:15:11",
tabs: [
{
title: "Twitch",
url: "https://www.twitch.tv/",
},
{
title: "reddit: the front page of the internet",
url: "https://www.reddit.com/",
},
],
title: "Social",
},
};
describe("removeTab", () => {
it("correctly adjusts groups and counts when a tab is removed", () => {
var tabs = init_groups["group-0"].tabs;
const { container } = render(<Tab init_tabs={tabs} />);
expect(container.getElementsByClassName("draggable").length).toEqual(3);
var removeTabSpy = jest.spyOn(TabFunc, "removeTab");
fireEvent.click(container.querySelector(".close-tab"));
expect(removeTabSpy).toHaveBeenCalledTimes(1);
expect(container.getElementsByClassName("draggable").length).toEqual(2); // fails (does not remove the tab for some reason)
});
});
I mocked the Chrome API according to my needs, but feel that something is missing. To mock the Chrome API I followed this post (along with many others, even for other test runners like Jasmine): testing chrome.storage.local.set with jest.
Even though the Chrome storage API is mocked, I think the issue lies in this function which gets called upon initial render. That is, I think the chrome.storage.local.get is not actually being executed, but am not sure why.
// ./src/Tab/Tab_functions.js
/**
* Sets the initial tabs based on Chrome's local storage upon initial render.
* If Chrome's local storage is empty, this is set to an empty array.
* #param {function} setTabs For re-rendering the group's tabs
* #param {string} id Used to get the correct group tabs
*/
export function setInitTabs(setTabs, id) {
chrome.storage.local.get("groups", (local) => {
var groups = local.groups;
setTabs((groups && groups[id] && groups[id].tabs) || []);
});
}
The reason I think the mocked Chrome storage API is not working properly is because when I manually set it in my tests, the number of tabs does not increase from 0. Which forced me to pass a prop (props.init_tabs) to my Tab component for testing purposes (https://github.com/lbragile/TabMerger/blob/f78a2694786d11e8270454521f92e679d182b577/src/Tab/Tab.js#L33-L35) - something I want to avoid if possible via setting local storage.
Can someone point me in the right direction? I would like to avoid using libraries like jest-chrome since they abstract too much and make it harder for me to understand what is going on in my tests.
I think I have a solution for this now, so I will share with others.
I made proper mocks for my chrome storage API to use localStorage:
// __mocks__/chromeMock.js
...
storage: {
local: {
...,
get: function (key, cb) {
const item = JSON.parse(localStorage.getItem(key));
cb({ [key]: item });
},
...,
set: function (obj, cb) {
const key = Object.keys(obj)[0];
localStorage.setItem(key, JSON.stringify(obj[key]));
cb();
},
},
...
},
...
Also, to simulate the tab settings on initial render, I have a beforeEach hook which sets my localStorage using the above mock:
// __tests__/Tab.spec.js
var init_ls_entry, init_tabs, mockSet;
beforeEach(() => {
chrome.storage.local.set({ groups: init_groups }, () => {});
init_ls_entry = JSON.parse(localStorage.getItem("groups"));
init_tabs = init_ls_entry["group-0"].tabs;
mockSet = jest.fn(); // mock for setState hooks
});
AND most importantly, when I render(<Tab/>), I noticed that I wasn't supplying the id prop which caused nothing to render (in terms of tabs from localStorage), so now I have this:
// __tests__/Tab.spec.js
describe("removeTab", () => {
it("correctly adjusts storage when a tab is removed", async () => {
const { container } = render(
<Tab id="group-0" setTabTotal={mockSet} setGroups={mockSet} />
);
var removeTabSpy = jest.spyOn(TabFunc, "removeTab");
var chromeSetSpy = jest.spyOn(chrome.storage.local, "set");
fireEvent.click(container.querySelector(".close-tab"));
await waitFor(() => {
expect(chromeSetSpy).toHaveBeenCalled();
});
chrome.storage.local.get("groups", (local) => {
expect(init_tabs.length).toEqual(3);
expect(local.groups["group-0"].tabs.length).toEqual(2);
expect(removeTabSpy).toHaveBeenCalledTimes(1);
});
expect.assertions(4);
});
});
Which passes!!
Now on to drag and drop testing 😊
I have an error in the console every time I'm deleting an item (List) in my Meteor application.
The error in the console is:
domrange.js:337 Uncaught Error: Must be attached
Here is the function, I can't understand where come from this error:
Lists.js
Meteor.methods({
'lists.remove'(listId) {
check(listId, String);
const list = Lists.findOne(listId);
if (list.owner !== this.userId) {
throw new Meteor.Error('not-authorized');
}
Tasks.remove({"listId": listId});
Lists.remove(listId);
},
All is working properly in the application but do you know where this error can come from ?
Ps: I'm using Blaze if it can help
thanks
It seems I found the solution adding a Meteor.isServer or better if (!this.isSimulation) (#MasterAM solution):
'lists.remove'(listId) {
check(listId, String);
const list = Lists.findOne(listId);
if (list.owner !== this.userId) {
throw new Meteor.Error('not-authorized');
}
if (!this.isSimulation) {
Tasks.remove({"listId": listId});
Lists.remove(listId);
}
},
I edited the working code with the help of #MasterAM It'w working now! No Console error anymore.