How to access props.children with testing-library/no-node-access - eslint

I have successfully installed eslint-plugin-testing-library and used overrides so it only warns me on code in test files.
However, it complains Avoid direct Node access. Prefer using the methods from Testing Library. for the following code props.children:
I want to be able to insert children, or a default node.
return (
<>
{ // Other elements here. }
{'children' in props ? (
props.children
) : (
<MyComponent {...props} disabled={disabled} />
)}
</>
)
What is wrong with this code? Why is props considered node access? How should I change it to satisfy the warning? Just add // eslint-disable-next-line testing-library/no-node-access?
Edit:
This is in a test file. It is creating an element in the same way as the main code. I do not understand why referencing props.children would warrant a warning. I wonder what is the justification for the warning and how else to perform the desired outcome.

Author of eslint-plugin-testing-library here! I'm sorry about this specific behavior being reported. Indeed, props.children is a valid usage and shouldn't be reported. Could you report this as a new issue? We can take a look at improving this rule in the future. Thanks!

Related

Eslint plugin for mobx that warns if you are using the store without an observer

Does it exist the eslint plugin that warns if i use mobx actions inside a component that is not wrapped in observer HOC:
const Comp1 = () => {
const store = useContext(rootContext)
return (
number: {store.number}
<button onClick={() => store.incByOne()}>increase number by 1</button>
)
}
export default Comp1 // warn on console
export default observer(Comp1) // fine
No, there is none, because it won't be possible for eslint to actually understand that you are using some sort of observable value. And observer could be defined in different ways too, not wrapping component inside one does not mean that you are not doing it somewhere else.
There is a configuration option for MobX though:
configure({ observableRequiresReaction: true })
Warns about any unobserved observable access. Use this if you want to check whether you are using observables without a "MobX context". This is a great way to find any missing observer wrappers, for example in React components. But it will find missing actions as well.

NixOS - Module imports with arguments

Let's say I have my NixOS configuration.nix set up as follows:
{config, pkgs, ...}:
{
services.openssh.enable = true;
}
I now want to have a second file called networking.nix which sets my hostname based on an argument.
{config, pkgs, hostname, ...}:
{
networking.hostName = hostname
}
Is this possible? How can I include the file. I already tried doing it by using imports = [ ./networking.nix { hostname = "helloworld"; } ]; but that didn't work.
Thanks.
A 'NixOS configuration file' is simply a module that doesn't define options, so there is really no distinction. A configuration.nix file is just a module, and typically it does not define any options, so it can be written in the abbreviated form.
Defining options is the normal way for NixOS modules to pass information around, so that's the most idiomatic way to go about.
However, if you really must, for some very special reason, because you're doing very unusual things with NixOS, you can put arbitrary functions in imports. But you shouldn't, because it doesn't work well with the module system's custom error messages and potentially other aspects that rely on knowing where a module is defined. If you do so, do make sure it is an actual function. In your case, that would imply modifying the first line of networking.nix to make it a curried function:
hostname: {config, pkgs, ...}:
Not very pretty in my opinion. Although it is very explicit about what is going on, it deviates from what is to be expected of a NixOS module.
I encountered this problem today and came up with a fairly simple solution recommended in the manual.
foobar.nix
{ lib, withFoo ? "bar", ... }:
# simple error checking to ensure garbage isn't passed in
assert lib.asserts.assertOneOf "withFoo" withFoo [
"bar"
"baz"
# other valid choices ...
];
{
# ...
}
configuration.nix
args#{ ... }:
{
imports = [
# ...
(
import ./foobar.nix (
args
// { withFoo = "baz"; }
)
)
# ...
];
}
This is ideal for 'one off' options in your configurations.
You should be able to use the _module.argsoption [1] to do that. So your configuration.nix would be like:
{config, pkgs, ...}:
{
_module.args.hostname = "ahostname";
services.openssh.enable = true;
}
However where the values are very simple it will probably be much easier to just set them directly, e.g. just define networking.hostname in configuration.nix. This section of the manual re. merging and priorities may be helpful also [2].
Further discussion:
The value of _module.args is indeed applied to all imported configurations (though the value will only be used in modules that directly refer to it, such as the pkgs value, the ... represents all the values that aren't referenced).
For passing arguments to modules it seems a good approach to me, but from your comments perhaps a different approach might be more suitable.
Another solution could be to flip the relationship in the imports: rather than a single common config that passes multiple different arguments instead multiple different configs import the common configuration. E.g.
$cat ./common.nix
{ services.openssh.enable = true; }
$cat ./ahostname.nix
{ imports = [ ./common.nix ]; networking.hostname = "ahostname"; }
The NixOS config in this Reddit comment looks like it uses this approach. There are quite a few other NixOS configurations that people have shared publicly online so you might find some useful ideas there. The points in the answer from Robert Hensing are very useful to bear in mind as well.
However it's hard to say what might be a better solution in your case without knowing a bit more about the context in which you want to use it. You could create a new SO question with some more information on that which might make it easier to see a more appropriate solution.

Jest - how to test if a component does not exist?

How do I check if a component is not present, i.e. that a specific component has not been rendered?
.contains receives a React Node or array of Nodes as an argument. Instead, use .find:
expect(wrapper.find('selector').exists()).toBeTruthy()
You can use enzymes contains to check if the component was rendered:
expect(component.contains(<ComponentName />)).toBe(false)
If you're using react-testing-library (I know the OP wasn't but I found this question via web search) then this will work:
expect(component.queryByText("Text I care about")).not.toBeInTheDocument();
You can query by Text, Role, and several others. See docs for more info.
Note: queryBy* will return null if it is not found. If you use getBy* then it will error out for elements not found.
Providing a slightly updated answer based on the documentation for enzyme-matchers's toExist. This will require you to install the enzyme-matchers package.
function Fixture() {
return (
<div>
<span className="foo" />
<span className="bar baz" />
</div>
);
}
const wrapper = mount(<Fixture />); // mount/render/shallow when applicable
expect(wrapper.find('span')).toExist();
expect(wrapper.find('ul')).not.toExist();
.contains does not expect a selector, unlike find. You can look at the length attribute of the ShallowWrapper
expect(wrapper.find('...')).toHaveLength(0)
I found I needed to use this syntax with Enzyme and Jest to test if a Connected Component existed in the rendered output.
We use Jest and Enzyme, and I've found the only good test is to import the sub-component and test this way:
expect(component.find(SubComponent).length).toEqual(0); // or (1) for exists, obvs
I tried all the other answers and none worked reliably.
If you are using react-testing-library, then this also will work:
expect(component.queryByText("Text I care about").toBeNull());
expect(within(component).queryByText("Text I care about")).toBeNull();
Note: In my case, I needed to use queryBy* because it doesn´t error out when the text element (that contains the text: Text I care about) does not exist. Therefore, I could evaluate whether there is an existence of a text component or not.

Is .hasOwnProperty() necessary with for..in in Node.js?

When I do for..in, can I dispense with the if (obj.hasOwnProperty(key)) {...} check in Node.js if I am careful never to modify Object.prototype myself?
Or if I require() some third party package that happens to modify Object.prototype, does that screw up the Object.prototype for my module too?
Can I dispense with the if (obj.hasOwnProperty(key)) {...} check in Node.js if I am careful never to modify Object.prototype myself?
No, because Object is global. Anyone that messes with it in any module you use (or, any module they use by proxy) and they've broken it for your code regardless of what you do. The property check is damage control. It's a check on the nature of someone mucking with you're implicitly inheriting from.
node_modules/breakit.js
Object.prototype.foobar = () => "borked";
module.exports = true;
run node..
> require('breakit');
true
> let a = {};
> for ( let k in a ) { console.log(k) }
foobar
> a.foobar();
borked
It's important that while the .hasOwnProperty is necessary for the for .. in loop, the loop itself is probably not necessary and better avoided in most cases. The air-bnb eslint style guide for instance bans looping over an object all together.
There is nothing specific in node that would warrant not having this check. If you are already using lodash you can use _.forOwn() https://lodash.com/docs#forOwn
Another option is:
Object.getOwnPropertyNames(yourObj)
.forEach(function(keyName) {
yourObj[keyName] // do stuff
});
Or continue doing the 'if' check, there's a few options, but I would definitely keep one of the checks in, your choice which.

Ignore certain TypeScript compile errors?

I am wondering if there is a way to ignore certain TypeScript errors upon compilation?
I basically have the same issues most people with large projects have around using the this keyword, and I don't want to put all my classes methods into the constructor.
So I have got an example like so:
TypeScript Example
Which seems to create perfectly valid JS and allows me to get around the this keyword issue, however as you can see in the example the typescript compiler tells me that I cannot compile that code as the keyword this is not valid within that scope. However I don't see why it is an error as it produces okay code.
So is there a way to tell it to ignore certain errors? I am sure given time there will be a nice way to manage the this keyword, but currently I find it pretty dire.
== Edit ==
(Do not read unless you care about context of this question and partial rant)
Just to add some context to all this to show that I'm not just some nut-job (I am sure a lot of you will still think I am) and that I have some good reasons why I want to be able to allow these errors to go through.
Here are some previous questions I have made which highlight some major problems (imo) with TypeScript current this implementation.
Using lawnchair with Typescript
Issue with child scoping of this in Typescript
https://typescript.codeplex.com/discussions/429350 (And some comments I make down the bottom)
The underlying problem I have is that I need to guarantee that all logic is within a consistent scope, I need to be able to access things within knockout, jQuery etc and the local instance of a class. I used to do this with the var self = this; within the class declaration in JavaScript and worked great. As mentioned in some of these previous questions I cannot do that now, so the only way I can guarantee the scope is to use lambda methods, and the only way I can define one of these as a method within a class is within the constructor, and this part is HEAVILY down to personal preference, but I find it horrific that people seem to think that using that syntax is classed as a recommended pattern and not just a work around.
I know TypeScript is in alpha phase and a lot will change, and I HOPE so much that we get some nicer way to deal with this but currently I either make everything a huge mess just to get typescript working (and this is within Hundreds of files which I'm migrating over to TypeScript ) or I just make the call that I know better than the compiler in this case (VERY DANGEROUS I KNOW) so I can keep my code nice and hopefully when a better pattern comes out for handling this I can migrate it then.
Also just on a side note I know a lot of people are loving the fact that TypeScript is embracing and trying to stay as close to the new JavaScript features and known syntax as possible which is great, but typescript is NOT the next version of JavaScript so I don't see a problem with adding some syntactic sugar to the language as people who want to use the latest and greatest official JavaScript implementation can still do so.
The author's specific issue with this seems to be solved but the question is posed about ignoring errors, and for those who end up here looking how to ignore errors:
If properly fixing the error or using more decent workarounds like already suggested here are not an option, as of TypeScript 2.6 (released on Oct 31, 2017), now there is a way to ignore all errors from a specific line using // #ts-ignore comments before the target line.
The mendtioned documentation is succinct enough, but to recap:
// #ts-ignore
const s : string = false
disables error reporting for this line.
However, this should only be used as a last resort when fixing the error or using hacks like (x as any) is much more trouble than losing all type checking for a line.
As for specifying certain errors, the current (mid-2018) state is discussed here, in Design Meeting Notes (2/16/2018) and further comments, which is basically
"no conclusion yet"
and strong opposition to introducing this fine tuning.
I think your question as posed is an XY problem. What you're going for is how can I ensure that some of my class methods are guaranteed to have a correct this context?
For that problem, I would propose this solution:
class LambdaMethods {
constructor(private message: string) {
this.DoSomething = this.DoSomething.bind(this);
}
public DoSomething() {
alert(this.message);
}
}
This has several benefits.
First, you're being explicit about what's going on. Most programmers are probably not going to understand the subtle semantics about what the difference between the member and method syntax are in terms of codegen.
Second, it makes it very clear, from looking at the constructor, which methods are going to have a guaranteed this context. Critically, from a performance, perspective, you don't want to write all your methods this way, just the ones that absolutely need it.
Finally, it preserves the OOP semantics of the class. You'll actually be able to use super.DoSomething from a derived class implementation of DoSomething.
I'm sure you're aware of the standard form of defining a function without the arrow notation. There's another TypeScript expression that generates the exact same code but without the compile error:
class LambdaMethods {
private message: string;
public DoSomething: () => void;
constructor(message: string) {
this.message = message;
this.DoSomething = () => { alert(this.message); };
}
}
So why is this legal and the other one isn't? Well according to the spec: an arrow function expression preserves the this of its enclosing context. So it preserves the meaning of this from the scope it was declared. But declaring a function at the class level this doesn't actually have a meaning.
Here's an example that's wrong for the exact same reason that might be more clear:
class LambdaMethods {
private message: string;
constructor(message: string) {
this.message = message;
}
var a = this.message; // can't do this
}
The way that initializer works by being combined with the constructor is an implementation detail that can't be relied upon. It could change.
I am sure given time there will be a nice way to manage the this keyword, but currently I find it pretty dire.
One of the high-level goals (that I love) in TypeScript is to extend the JavaScript language and work with it, not fight it. How this operates is tricky but worth learning.

Resources