dojo problems with creating new dom nodes - dom

I am trying to create a new node that is a child of an existing ul node I have in the document, but no matter how I proceed I seem to get an error. The following two ways are the ways I have tried:
var ul = dojo.query('#highlights ul').0;
dojo.place("<li></li>", ul);
and I get a message:
TypeError: refNode.appendChild is not
a function
This message didn't make sense to me because on checking the value of ul I find that it is an element and it has two children already...I went on to try the more programmatic build allowed by dojo.create(); via the following lines:
var ul = dojo.query('#highlights ul').0;
dojo.create("li", null, ul);
and this produced an error:
TypeError: doc is undefined
which is really baffling me since the ul element is defined...I decided that I should just try adding the same li element to the doc body, so I went and tried:
dojo.create("li", null, dojo.body());
which returned without error, but on checking the document source nothing changed....So is there something I am missing? I assume that I don't need to require any files to use these, is that an incorrect assumption? the load function that contains this code is in an external file to help me organize my code, could this be causing the problem?
this function is called in the dojo.addOnLoad block to prevent problems when called async, could this be part of the problem?

Your problem is that you're not getting the node from your query.
It should be:
var ul = dojo.query('#highlights ul')[0];
not
var ul = dojo.query('#highlights ul').0;
I'm surprised your browser didn't error on the dojo.query line.

Probably xenador forgot to enclose dom manipulations in dojo.ready. doc is underfined == Document wasn't ready.

Related

How do I clear an element before rendering?

I have inherited an older project using jquery.
I am modernising the code.
In particular this $(selector).html("<h1>lol</h1>"); which as far as I understand is a full replacement of the selectors content.
I always end up with an error if I try to render to a cleared element.
This code:
const appDiv: HTMLElement = document.getElementById('app');
appDiv.innerHTML = `<h1>TypeScript Starter</h1>`;
// trying to replace jquery $(selector).html("<h1>lol</h1>");
appDiv.innerHTML = '';
render(html`<h1>lol</h1>`, appDiv);
appDiv.innerHTML = '';
render(html`<h1>lol</h1>`, appDiv);
Or see my stackblitz
I always get the following error:
Error in lit-html.js (93:55)
Cannot read properties of null (reading 'insertBefore')
Do you know what I am missing? 🧐
Thanks!
Note: This is a duplicate of my question (and based on a suggested technique) from a closed Lit Github Issue
Note: Maybe I am talking rubbish. I can't find a clear answer if render REPLACES content or APPENDS content. A concrete answer on that would be fine!
Lit v1 will clear the container before rendering the first time. Lit v2 will not.
Only clear the existing container content once before using render. After that render will correctly update content from previous render calls.
const appDiv: HTMLElement = document.getElementById('app');
appDiv.innerHTML = `<h1>TypeScript Starter</h1>`;
// trying to replace jquery $(selector).html("<h1>lol</h1>");
appDiv.innerHTML = '';
render(html`<h1>lol</h1>`, appDiv);
render(html`<h1>lol2</h1>`, appDiv);

Virtualized AutoComplete Error - Invalid prop `children` supplied to `ForwardRef(ListboxComponent)`

The Autocomplete Virtualization example at https://mui.com/components/autocomplete/#main-content produces and error in the console advising:
Failed prop type: Invalid prop children supplied to ForwardRef(ListboxComponent), expected a ReactNode.
Does anyone know what the error is referring to? The example works but I'd like to know where the error is coming from to better understand the example 🤓
The error seems to be coming directly from line 109-111 where the the propTypes of children are specifically being defined as node (Typechecking). Because children is not a node, the error is thrown.
ListboxComponent.propTypes = {
children: PropTypes.node,
};
If these lines are commented out, the error goes away; but, are the children supposed to be nodes? It would seem they should be per these lines being added to ensure such but then why is it working without. Does anyone know of any documentation/articles explaining this example in a little more depth?

Stop huge error output from testing-library

I love testing-library, have used it a lot in a React project, and I'm trying to use it in an Angular project now - but I've always struggled with the enormous error output, including the HTML text of the render. Not only is this not usually helpful (I couldn't find an element, here's the HTML where it isn't); but it gets truncated, often before the interesting line if you're running in debug mode.
I simply added it as a library alongside the standard Angular Karma+Jasmine setup.
I'm sure you could say the components I'm testing are too large if the HTML output causes my console window to spool for ages, but I have a lot of integration tests in Protractor, and they are SO SLOW :(.
I would say the best solution would be to use the configure method and pass a custom function for getElementError which does what you want.
You can read about configuration here: https://testing-library.com/docs/dom-testing-library/api-configuration
An example of this might look like:
configure({
getElementError: (message: string, container) => {
const error = new Error(message);
error.name = 'TestingLibraryElementError';
error.stack = null;
return error;
},
});
You can then put this in any single test file or use Jest's setupFiles or setupFilesAfterEnv config options to have it run globally.
I am assuming you running jest with rtl in your project.
I personally wouldn't turn it off as it's there to help us, but everyone has a way so if you have your reasons, then fair enough.
1. If you want to disable errors for a specific test, you can mock the console.error.
it('disable error example', () => {
const errorObject = console.error; //store the state of the object
console.error = jest.fn(); // mock the object
// code
//assertion (expect)
console.error = errorObject; // assign it back so you can use it in the next test
});
2. If you want to silence it for all the test, you could use the jest --silent CLI option. Check the docs
The above might even disable the DOM printing that is done by rtl, I am not sure as I haven't tried this, but if you look at the docs I linked, it says
"Prevent tests from printing messages through the console."
Now you almost certainly have everything disabled except the DOM recommendations if the above doesn't work. On that case you might look into react-testing-library's source code and find out what is used for those print statements. Is it a console.log? is it a console.warn? When you got that, just mock it out like option 1 above.
UPDATE
After some digging, I found out that all testing-library DOM printing is built on prettyDOM();
While prettyDOM() can't be disabled you can limit the number of lines to 0, and that would just give you the error message and three dots ... below the message.
Here is an example printout, I messed around with:
TestingLibraryElementError: Unable to find an element with the text: Hello ther. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
...
All you need to do is to pass in an environment variable before executing your test suite, so for example with an npm script it would look like:
DEBUG_PRINT_LIMIT=0 npm run test
Here is the doc
UPDATE 2:
As per the OP's FR on github this can also be achieved without injecting in a global variable to limit the PrettyDOM line output (in case if it's used elsewhere). The getElementError config option need to be changed:
dom-testing-library/src/config.js
// called when getBy* queries fail. (message, container) => Error
getElementError(message, container) {
const error = new Error(
[message, prettyDOM(container)].filter(Boolean).join('\n\n'),
)
error.name = 'TestingLibraryElementError'
return error
},
The callstack can also be removed
You can change how the message is built by setting the DOM testing library message building function with config. In my Angular project I added this to test.js:
configure({
getElementError: (message: string, container) => {
const error = new Error(message);
error.name = 'TestingLibraryElementError';
error.stack = null;
return error;
},
});
This was answered here: https://github.com/testing-library/dom-testing-library/issues/773 by https://github.com/wyze.

How do I test if an img tag exists?

if I do expect(img).not.toBe(null) then I get an error:
Error: expect called with WebElement argment, expected a Promise. Did you mean to use .getText()?. I don't want to get the text inside an img, I just want to know if the tag exists on the page.
describe('company homepage', function() {
it('should have a captcha', function() {
var driver = browser.driver;
driver.get('http://dev.company.com/');
var img =driver.findElement(by.id('recaptcha_image'));
expect(img.getText()).not.toBe(null);
});
});
Passes but I'm not sure it is testing the right thing. Changing the id to something that doesn't exist does fail.
How do I properly test for a tag to exist with protractor in a non-angular app context?
Edit 2:
Per Coding Smackdown below, an even shorter answer is now available in protractor:
expect(element(by.id('recaptcha_image')).isPresent()).toBe(true);
Edit 1:
I discovered isElementPresent() today which is just a more readable shortcut for what I described below. See: http://www.protractortest.org/#/api
Usage for you would be:
driver.isElementPresent(by.id('recaptcha_image')).then(function(present){
expect(present).toBe(false);
})
Old answer (this works but the above is more reader friendly)
In general you should use findElements (or $$ which is an alias for findElements by css) if you're not sure a tag will be there. Then test for the array length. FindElement (and $) will just throw an error if it cant find the element.
Therefore instead of
var img =driver.findElement(by.id('recaptcha_image'));
expect(img.getText()).not.toBe(null);
use:
driver.findElements(by.id('recaptcha_image')).then(function(array){
expect(array.length).not.toBe(0);
})
Also, getText() returns a promise which is why you're getting that error.
Using the latest Protractor build you can shorten it down to the following:
expect(element(by.id('recaptcha_image')).isPresent()).toBe(true);

Locating text within a div's ul/li

using .NET MVC/Razor, I am working on setting the validation summary manually client side using the following method for a few js client side operations which will not be handled in data annotations:
function RenderError(message) {
var myDiv = $('[data-valmsg-summary="true"]');
myDiv.removeClass("validation-summary-valid");
myDiv.addClass("validation-summary-errors");
var list = myDiv.find('ul');
$("<li />").html(message).appendTo(list);
}
This works fine, but obviously repeats the errors. What is the simplest way to check and see if the message has already been entered in a list item? Keeping in mind that I already have a handle to the div itself?
Thanks in advance
You could check in a if statement if the data-valmsg-summary field is true and skip it accordingly, does it make sense?