I'm new to React-Testing-Library and found a couple of examples on the web of people using view.getByText('Greeting') and screen.getByText('Greeting'), like in the following code.
Is there any difference between them?
import React from 'react'
import { render, screen } from '#testing-library/react'
import '#testing-library/jest-dom/extend-expect'
import { App } from "./App";
test("render the correct context", ()=>{
const view = render(<App />);
view.getByText("Greeting");
screen.getByText("Greeting");
});
Can anyone please tell me in detail?
TLDR; They are very often the same thing.
The difference
getByText will query inside baseElement
screen.getByText will query inside document.body
We usually don't specify a custom container or baseElement inside the render function, this causes it to default to document.body.
Therefore getByText and screen.getByText--or any of the other queries--are usually interchangeable.
import { render, screen } from '#testing-library/react'
test("render the correct context", ()=>{
const { getByText } = render(<App />, { baseElement });
getByText("Greeting"); // queries inside baseElement (which usually means document.body)
screen.getByText("Greeting"); // queries inside document.body
});
Which one should you use
I don't think this matters much and you should be fine either way. That said, the creator of the library advocates for screen and also mentions you should avoid using the container or baseElement render options.
Useful links
why you should use screen
screen docs
render options
The view is just the result of render, so in the docs we see:
The render method returns a promise which resolves with an object that
has a few properties:
...queries#
The most important feature of render is that the queries from DOM
Testing Library are automatically returned with their first argument
bound to the results of rendering your component.
So you have your objected generated by your App, that you can query. screen is
screen#
All of the queries exported by DOM Testing Library accept a container
as the first argument. Because querying the entire document.body is
very common, DOM Testing Library also exports a screen object which
has every query that is pre-bound to document.body (using the within
functionality).
So querying here queries the entire body always.
Related
https://jsfiddle.net/78mLj9vb/
class App extends Vue {
message = 'Hello!';
shrek;//属性 property
constructor(){
super();
this.shrek = "This is my swamp!";//代入-assignment
//"This is my swamp!"がコンソールで出力されている Prints as it should
console.log(this.shrek);
this.print();
}
print(){
console.log(this.shrek);//[undefined]が出力されている Undefined printed to console
}
}
I'm learning Vuejs with class components and typescript. I do not understand why I can't access the fields of my class within methods. They are always undefined. I have tried doing the initial assignment to the field inline along with the property declaration, and I have also tried doing the assignment in the constructor. I imagine it's the Vuejs data binding mangling the class fields in a way that I do not understand, I have tried accessing them through this.$data to no avail. I understand it's probably not good design to have data that is unrelated to presentation in a component class, but this time around I don't have a database so I'm trying to hard code some data into a class method to fake it, so that I can then loop over the data w/v-for to create a select list. I've included a fiddle that looks nothing like what I'm actually trying to do, but illustrates the "issue" (my lack of understanding really).
How do you declare normal class fields outside of the Vuejs data-binding magic, or alternatively, how do you access the data that has been bound and changed by Vue?
For the best use change you code to this:
//...
#Component({
template: `
<div>
<h1>{{ message }}</h1>
<h1>{{ shrek }}</h1>
</div>
`
})
class App extends Vue {
data(){
return {
shrek: 'test',
message: 'Hello world!'
};
}
created(){
this.shrek = "This is my swamp!";
console.log(this.shrek);
this.print();
}
print(){
console.log(this.shrek);
}
}
new Vue({
el: '#app',
render: h => h(App)
})
//...
On your link here
After having practiced using Vue for a few more weeks and researching various topics on the internet I have come to the conclusion (which should have been obvious to me at first) that the answer is to use components only for what components are good for. That is to say, if you have some logic that gets gnarly and you want to alleviate it with helper functions, those helper functions can be declared outside the class as regular functions and used within the component code. Another upside of this approach is that if multiple components would get use out of your helper function or initialization code, you can instead move it into a typescript or javascript module and import it into those components that need it.
データ初期化や普通の論理を実施するヘルパー関数をコンポーネント内に置くより別の標準なTypescriptやJavascript関数に置いた方が良さそうです。Vuejsのコンポーネント・クラスの良い点はview作りだけでviewと関係ない論理をコンポーネント以外に置くべきです。それにそうするとその論理を別のファイルに置いてモジュール形で複数のコンポーネントはその論理を使えるようになります。
I am creating a web-based presentation using RemarkJS, my preferred tool for presentations. Since I want to demo small bits of nodejs code, I want to use RunKit's REPL embedding capability. I couldn't quite figure out how to embed multiple instances on a single web page, but I managed to kludge something up by running the following code multiple times
var nb1 = RunKit.createNotebook({
// the parent element for the new notebook
element: document.getElementById("div1"),
// specify the source of the notebook
source: source1
})
var nb2 = RunKit.createNotebook({
// the parent element for the new notebook
element: document.getElementById("div2"),
// specify the source of the notebook
source: source2
})
and so on. This actually works, but is super-inefficient. When I launch my presentation, multiple calls to RunKit are made even though the entire page is loaded only once. Not only that, multiple calls to RunKit are made every time I change the slides, which, in RemarkJS, simple hides and displays different parts of the same, single web page. Since the web page itself is being loaded only once, RunKit should be called only once. At least, that is what I think (obviously, it seems I am wrong).
Finally, the actual RunKit REPL frame takes a while before it is rendered. In the beginning, only a few lines of truncated code shows up, but after a while of waiting, the entire frame gets rendered.
What am I doing wrong? Is there a better way of doing this?
I had the same problem and figured it out. So for future users here is how you do it.
<script src="https://embed.runkit.com"></script>
<style>.embed { overflow: visible; }</style>
<pre class="embed" data-gutter="inside">console.log("hello inside");
1 + 1</pre>
<pre class="embed" data-gutter="outside">console.log("hello outside");
1 + 1</pre>
<pre class="embed" data-gutter="none">console.log("hello none");
1 + 1</pre>
<script>
const elements = [...document.getElementsByClassName('embed')]
const notebooks = elements.reduce((notebooks, element) => {
const innerText = element.firstChild
const currentCell = window.RunKit.createNotebook({
element,
gutterStyle: element.getAttribute("data-gutter"),
source: innerText.textContent,
// Remove the text content of the pre tag after the embed has loaded
onLoad: () => innerText.remove()
})
return notebooks
}, [])
</script>
The sample is taken from here: https://runkit.com/docs/embed
Scroll down and you will find it.
React Developer Tools give a lot of power to inspect the React component tree, and look at props, event handlers, etc. However, what I'd really like to do is to be able to inspect those data structures in the browser console.
In chrome I can play with the currently selected DOM element in the console using $0. Is there a way to extract React component info from $0, or is it possible to do something similar with the React Dev Tools?
Using React Developer Tools you can use $r to get a reference to the selected React Component.
The following screenshot shows you that I use React Developer Tools to select a component (Explorer) which has a state-object callednodeList. In the console I can now simply write $r.state.nodeList to reference this object in the state. Same works with the props (eg.: $r.props.path)
An answer to your question can be found here in a similar question I asked:
React - getting a component from a DOM element for debugging
I'm providing an answer here because I don't have the necessary reputation points in order to mark as duplicate or to comment above.
Basically, this is possible if you are using the development build of react because you can leverage the TestUtils to accomplish your goal.
You need to do only two things:
Statically store the root level component you got from React.render().
Create a global debug helper function that you can use in the console with $0 that accesses your static component.
So the code in the console might look something like:
> getComponent($0).props
The implementation of getComponent can use React.addons.TestUtils.findAllInRenderedTree to search for match by calling getDOMNode on all the found components and matching against the passed in element.
Open console (Firefox,Chrome) and locate any reactjs rendered DOM element or alternatively execute js script to locate it:
document.getElementById('ROOT')
Then check for element properties in object property viewer for attributes with name beginning like '__reactInternalInstace$....' expand _DebugOwner and see stateNode.
The found stateNode will contain (if it has) 'state' and 'props' attributes which is used heavily in reactjs app.
Though the accepted answer works, and is a great method, in 2020 you can now do a lot of inspection without using the $r method. The Components tab of React DevTools will show you props and detailed state when you select the relevant component (make sure you're on the right level), as well as let you do other things like suspend it or inspect the matching DOM element (little icons in the top right).
Assign the state or prop object to the window object:
window.title = this.state.title
And then from the dev tools console you can try different methods on the exposed object such as:
window.title.length
8
You can attach a reference to the window object like
import { useSelector } from "react-redux";
function App() {
// Development only
window.store = useSelector((state) => state);
return (
<div className="App">
</div>
);
}
export default App;
Then access it from the console
store
{states: {…}}
states:
someProperty: false
[[Prototype]]: Object
[[Prototype]]: Object
[Console][1]
[1]: https://i.stack.imgur.com/A4agJ.png
Say I wrote a blog app in Sails.js.
On every page in this app, there is a sidebar widget called "Recent Posts", where it lists the titles of the 5 most recent posts and clicking on them takes you to the post in question.
Because this sidebar widget is present on every page, it should be in layout.ejs. But, here we have a conflict - dynamic content is only supposed to be pulled from the database in the controller action for rendering a specific view.
This dynamic content isn't for a specific view, it's for the whole site (via layout.ejs).
By the conventions that I understand, I'd have to get that dynamic content data for the sidebar widget in every controller action that renders a view (otherwise I would get an undefined error when I attempt to call that local in my layout.ejs file).
Things I've tried / considered:
Load that dynamic content in every controller action that renders a view (this solution is very bad) and calling that dynamic content in layout.ejs as if it were a local for the specific view. This works fine, but goes against D.R.Y. principles and quite frankly is a pain in the ass to have to run the same query to the database in every controller action.
As per another similar stackoverflow question, create a new config (E.G. config/globals.js), load my dynamic content from my database into that config file as a variable, and then calling sails.config.globals.[variable_name] in my layout.ejs file. This also worked, since apparently config variables are available everywhere in the application -- but it 's a hacky solution that I'm not a fan of (the content I'm loading is simply the titles and slugs of 5 recent posts, not a "global config option", as the solution implies).
Run the query to get the dynamic content inside the .EJS file directly between some <% %> tags. I'm not sure if this would work, but even if it did, it goes against the separation of concerns MVC principle and I'd like to avoid doing this if at all possible (if it even works).
As per a lengthy IRC discussion # http://webchat.freenode.net/?channels=sailsjs, it was suggested to create a policy and map that policy to all my controllers. In that policy, query the database for the 5 most recent posts, and set them to the req.recentposts. The problem with this solution is that, while the recent posts data will be passed to every controller, I still have to pass that req.recentposts data to my view -- making it so I still have to modify every single res.view({}) in every action. I don't have to have the database query in every action, which is good, but I still have to add a line of code to every action that renders a view... this isn't D.R.Y. and I'm looking for a better solution.
So, what is the proper solution, without needing to load that dynamic content in every controller action (a solution that adheres to D.R.Y. is what I'm lookng for), to get some dynamic content available to my layout.ejs file?
In folder /config you should create a file express.js and add something like that:
module.exports.express = {
customMiddleware: function(app){
app.use(function(req, res, next){
// or whatever query you need
Posts.find().limit(5).exec(function(err, posts){
res.locals.recentPosts = posts;
// remember about next()
next();
});
});
}
}
Then just make some simple loop in your view:
<% for(var i=0; i<recentPosts.length; i++) { %>
<% recentPosts[i].title %>
<% } %>
Here are some links to proper places in documentation:
https://github.com/balderdashy/sails-docs/blob/0.9/reference/Configuration.md#express
and
https://github.com/balderdashy/sails-docs/blob/0.9/reference/Response.md#reslocals
I found out another way to do this. What I did was to create a service that could render .ejs files to plain html by simply taking advantage of the ejs library already in sails. This service could either be invoked by the controller, or even passed as a function in the locals, and executed from within the .ejs. The service called TopNavBarService would look like:
var ejs = require('ejs');
exports.render = function() {
/* database finds goes here */
var userInfo = {
'username' : 'Kallehopp',
'real_name' : 'Kalle Hoppson'
};
var html = null;
ejs.renderFile('./views/topNavBar.ejs', {'locals':userInfo}, function(err, result) { html = result; });
return html;
}
In the constroller it could look like:
module.exports = {
testAction: function (req, res) {
return res.view('testView', {
renderNavbar: TopNavBarService.render // service function as a local!
});
}
};
This way you can create your customized ejs-helper that could even take arguments (although not shown here). When invoked, the helper could access the database and render a part of the html.
<div>
<%- renderNavbar() %>
</div>
Inside a meteor template helper function, is there any difference in performance, number of re-renders, or anything else if I return the result of a find vs a fetch?
For example, the find approach:
Template.players.topScorers = function () {
return Users.find({score: {$gt: 100}}, {sort: {score: -1}});
};
Or adding a fetch:
Template.players.topScorers = function () {
return Users.find({score: {$gt: 100}}, {sort: {score: -1}}).fetch();
};
The find-only approach is what is currently in the docs, but I’ve seen lots of other people using fetch.
Yes there is.
By using fetch you register a dependency on the entire query result set on the spot. By using find and later on iterating using {{#each}} a dependency is registered on every document separately. So when one document changes, only the relevant code is re-rendered. When using fetch, changing any document in the result-set would re-render the entire scope in which you used fetch.
For small result-sets it doesn't make any difference. For larger sets with frequent changes it could slow down computation and cause undesired visual artefacts.
I wrote a post which may help you understand it (it doesn't answer your question directly though)
This is what we follow in Oodles Technologies.
For defining helper just go to your template js file for example if you have a template name as allInventory so just go to allInventory.js file and write the helper as follows:-
Template.allInventory.helpers({
})
make a function inside this helper in which you put your logic for getting data from Database or Session or from other service and than use that in you html like:-
Template.allInventory.helpers({
productDetails: function() {
return Session.get('dbData');
}
})
On html side you just need to use the function name as follows:-
{{#each productInfo in productDetails}}
<div class="imgb"><img src="{{productInfo.image_url}}"></div>
{{productInfo.item_name}}
{{productInfo.seller_sku}}
{{productInfo.quantity}}
{{productInfo.price}}
<a type="button" class="full-view text-success"><i id="fullView" data="{{productInfo._id}}" class="fa fa-eye"></i></a>
{{/each}}
As you can see in above productDetails a function name in your helper class on which you get the data you want to render on your Html is accessible directly via that name and you can traverse that via each loop in html templates.