org_scalajs_dom_raw_HTMLDocument(...).createRange is not a function - scala.js

I'm upgrading scalatags from 0.6.7 to 0.9.3 as part of upgrading scalaJS from 0.6.x to 1.4.0.
I got the following error in some of my tests:
scala.scalajs.js.JavaScriptException: TypeError: $m_Lorg_scalajs_dom_package$(...).document__Lorg_scalajs_dom_raw_HTMLDocument(...).createRange is not a function
Tracing the code, I believe it occurs while executing line 141 of the following scalatags code in `scalatags.JsDom:
I extracted just the createRange call into a separate test and got the same error. "creating range" was printed; "created range" was not and it produced the same exception as above.
createRange() is a native function.
Googling "createRange is not a function" yields a number of similar issues, all seem to be related to testing (but not with ScalaJS). Many of them indicate the "fix" is to monkey-patch document with your own version of createRange. Really?
I initially thought this was an issue with scalatags. Then I thought it's with the scalajs library. Now I'm thinking it's something with Node.js, although Google is not producing any smoking guns.
Suggestions on how to proceed? Try to monkey patch document?

Summary: jsdom appears to be missing the document.createRange function when using Node.js for testing. Others in other languages have similar problems.
The following monkey patch worked for me. After developing this, I noticed that Facade Types has a section on monkey typing.
Also, the library code that tickled this bug (scalatags) actually calls document.createRange().createContextualFragment(v). So I needed to provide something for that as well.
import scala.scalajs.js
import org.scalajs.dom.document
js.Dynamic.global.document.createRange = () ⇒
js.Dynamic.literal(
setStart = () => js.Dynamic.literal(),
setEnd = () => js.Dynamic.literal(),
commonAncestorContainer = js.Dynamic.literal(
nodeName = "BODY",
ownerDocument = document
),
createContextualFragment = (v: String) ⇒ {
val p = document.createElement("p")
p.appendChild(document.createTextNode(v))
}
)

Related

How to apply a decorator with arguments to an imported function

This similar to a previous question but not quite.
Like the other question, I want to apply a decorator to an imported function, but in my case, my decorator requires arguments
Working
from flask_restx import Namespace
from . import exceptions as e
api = Namespace('v2', 'API Version 2' )
#api.errorhandler(e.MissingPrompt)
def handle_bad_requests(error):
'''Namespace error handler'''
logger.warning(error.log)
return({'message': error.specific}, error.code)
But I want to move handle_bad_requests() to its own file
so I want it like
from flask_restx import Namespace
from . import exceptions as e
api = Namespace('v2', 'API Version 2' )
#api.errorhandler(e.MissingPrompt)
e.handle_bad_requests # ??
I tried like the other answers here suggested like this
handle_bad_requests = api.errorhandler(e.handle_bad_requests, e.MissingPrompt)
But that just gives me an error I am sending too many arguments
I just discovered the answer nested within the comments of a previous answer
handle_bad_requests = api.errorhandler(e.MissingPrompt)(e.handle_bad_requests)
And that seems to work fine.
The double parentheses would never have occured to me

How to provide an explicit error/failure message in the Scala fastparse library?

I'm using Li Haoyi's FastParse library. I have several situations where I'd like to provide explicit failure messages.
For example:
def courseRE[p: P]: P[Regex] =
P(CharIn("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.|*+[]()-^$").repX(1).!).map { re =>
try { re.r }
catch { case e => failure(s"Ill-formed regular expression: ${re}.") }
}
But there is (apparently) no failure function.
Any suggested work-arounds? Simply throwing an exception doesn't give any context information.
I haven't yet found a good solution. I don't like the solution proposed by #user2963757 because it loses all the information from the parser about what it was looking for, where it was looking, etc.
This is raised a number of times in the FastParse issues list on GitHub. See issue 213, issue 187, issue 243, and pull request 244. There are a few vague suggestions but as far as I can tell the pull request hasn't been acted on (as of 2023-02-09).
The best I've found so far is defining this in an accessible location:
// Fail with a message. See https://github.com/com-lihaoyi/fastparse/issues/213
// The message shows up as "Expected ..."; phrase it appropriately.
private def Fail[T](expected: String)(implicit ctx: P[_]): P[T] = {
val res = ctx.freshFailure()
if (ctx.verboseFailures) ctx.setMsg(ctx.index, () => expected)
res
}
To use it:
P(CharIn("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.|*+[]()-^$").repX(1).!).flatMap(re =>
Try(re.r)
.map(Pass(_))
.getOrElse(Fail("<Well-formed regular expression>"))
)
Trying to parse "^CS1[1345" yields
Expected <Well-formed regular expression>:1:10, found ""
Notice that the failure message has to be stated in terms of what was expected, not the actual problem. The actual error message thrown by the exception usually doesn't work well in this situation. I'm also not getting the fragment that it found.
Unfortunately, even this message is usually unavailable. For example, parsing a larger piece of my input results in
Expected (courseSpecDef | minUnits | xOf | courseSpec):1:14, found "^CS1[1345 "
I'd like to be able to surface the more exact error of "Unclosed character class" but seemingly can't.
By the way, I looked in the documentation, source code, and the sample parsers (PythonParse and ScalaParse) for examples of the use of the Fail parser. Can't find any. The only one is the one shown in the documentation, which doesn't compose with another parser.
If anyone has a better solution, I'd still love to hear it.

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 to get PyTest fixtures to autocomplete in PyCharm (type hinting)

I had a bear of a time figuring this out, and it was really bugging me, so I thought I'd post this here in case anyone hit the same problem...
(and the answer is so dang simple it hurts :-)
The Problem
The core of the issue is that sometimes, not always, when dealing with fixtures in PyTest that return objects, when you use those fixtures in a test in PyCharm, you don't get autocomplete hints. If you have objects with large numbers of methods you want to reference while writing a test, this can add a lot of overhead and inconvenience to the test writing process.
Here's a simple example to illustrate the issue:
Let's say I've got a class "event_manager" that lives in:
location.game.events
Let's further say that in my conftest.py file (PyTest standard thing for the unfamiliar), I've got a fixture that returns an instance of that class:
from location.game.events import event_manager
...
#pytest.fixture(scope="module")
def event_mgr():
"""Creates a new instance of event generate for use in tests"""
return event_manager()
I've had issues sometimes, (but not always - I can't quite figure out why) with classes like this where autocomplete will not work properly in the test code where I use the fixture, e.g.
def test_tc10657(self, evt_mgr):
"""Generates a Regmod and expects filemod to be searchable on server"""
evt_mgr.(This does not offer autocomplete hints when you type ".")
So the answer is actually quite simple, once you review type hinting in PyCharm:
http://www.jetbrains.com/help/pycharm/2016.1/type-hinting-in-pycharm.html
Here's how to fix the above test code so that autocomplete works properly:
from location.game.events import event_manager
...
def test_tc10657(self, evt_mgr: event_manager):
"""Generates a Regmod and expects filemod to be searchable on server"""
evt_mgr.(This DOES offer hints when you type "." Yay!)
Notice how I explicitly type the fixture as an input parameter of type event_manager.
Also if you add a docstring to a function and specify the type of the the parameters, you will get the code completion for those parameters.
For example using pytest and Selenium:
# The remote webdriver seems to be the base class for the other webdrivers
from selenium.webdriver.remote.webdriver import WebDriver
def test_url(url, browser_driver):
"""
This method is used to see if IBM is in the URL title
:param WebDriver browser_driver: The browser's driver
:param str url: the URL to test
"""
browser_driver.get(url)
assert "IBM" in browser_driver.title
Here's my conftest.py file as well
import pytest
from selenium import webdriver
# Method to handle the command line arguments for pytest
def pytest_addoption(parser):
parser.addoption("--driver", action="store", default="chrome", help="Type in browser type")
parser.addoption("--url", action="store", default='https://www.ibm.com', help="url")
#pytest.fixture(scope='module', autouse=True)
def browser_driver(request):
browser = request.config.getoption("--driver").lower()
# yield the driver to the specified browser
if browser == "chrome":
driver = webdriver.Chrome(executable_path='/path/to/chromedriver')
else:
raise Exception("No driver for browser " + browser)
yield driver
driver.quit()
#pytest.fixture(scope="module")
def url(request):
return request.config.getoption("--url")
Tested using Python 2.7 and PyCharm 2017.1. The docstring format is reStructuredText and the "Analyze Python code in docstrings" checkbox is checked in settings.

making a GET request to a webservice from the playframework 2.0

I'm trying to call a webservice from the play framework, and I think I'm doing it wrong. I have an example call to http://www.myweather2.com/developer/forecast.ashx?uac=eDKGlpcBQN&query=52.6%2C-4.4&output=xml
A snippet from what I'm trying from the playframework is the following:
val response = WS.url("http://www.myweather2.com/developer/forecast.ashx?uac=eDKGlpcBQN&query=52.6%2C-4.4&output=xml").get.get()
val body = response.getBody
When I call this, the body consists of "useraccount does not exist". When I just put this url in a browser, I get the response I'm looking for. What am I doing wrong here?
For some reason, I was getting WS from the wrong import. When I fixed the imports to import play.api.libs.ws.WS, it worked. I'm still amazed it worked halfway with the wrong import
Don't know about "useraccount does not exist" but this seems to work:
val promise = WS.url("http://www.myweather2.com/developer/forecast.ashx?uac=eDKGlpcBQN&query=52.6%2C-4.4&output=xml").get()
val body = promise.value.get.body
Edit: Removed the space.
Also make sure your editor is not inserting a \n or \r after ?
I know this is old, but I just solved this problem while trying to do the same thing - getting the same results.
GET variables must be passed with WS.url("http://...").setQueryParameter(key, value)
Example:
val promise = WS.url("http://www.myweather2.com/developer/forecast.ashx").setQueryParameter("uac", "eDKGlpcBQN").setQueryParameter("query", "52.6%2C-4.4").setQueryParameter("output", "xml").get()
Annoying, but a relatively simple fix.