dom-testing-library
dom-testing-library copied to clipboard
Make screen.logTestingPlaygroundURL() work with document.head
Describe the feature you'd like:
Following on from #780, I think it would be helpful if screen.logTestingPlaygroundURL()
created a URL that also contains the markup from the document head. This would allow a better debugging experience for CSS-in-JSS solutions, but I imagine it would also improve the behaviour for any styling that isn't defined inline.
Suggested implementation:
Looks like https://testing-playground.com itself would need to change, maybe accepting a hash along the lines of #body-markup=<encoded-body-markup>&head-markup=<encoded-head-markup>
. I'll have a look through the code there and possibly open an issue in that repo too.
I've spent a little time exploring if this approach would be possible, using with the code below:
import React from "react";
import styled from "styled-components";
import { screen, render } from "@testing-library/react";
const StyledThing = styled.div`
background: #f0f;
color: #0f0;
`;
describe("test", () => {
it("renders a styled thing", () => {
const text = "I am a styled thing";
const { getByText } = render(<StyledThing>{text}</StyledThing>);
screen.logTestingPlaygroundURL();
expect(getByText(text)).toBeInTheDocument();
});
});
This outputs this url - which unfortunately does not have the beautiful colours I have defined. However, if I set a breakpoint on the line screen.logTestingPlaygroundURL();
and run window.document.head.innerHTML
I get the output '<style data-styled="active" data-styled-version="5.2.1">.fUmfxz{background:#f0f;color:#0f0;}</style>'
. So I am assuming it would be a matter of amending getPlaygroundUrl
to output both the markup for the body and the head.
Describe alternatives you've considered:
I haven't considered any alternatives.
Teachability, Documentation, Adoption, Migration Strategy:
I am assuming no teaching or documentation would be required, as the usage would remain the same.
A problem I can see with this is we have a hard limit on the amount of stuff we can include in that URL (URLs have a limited length). So if we include the head
and that has a bunch of <style>
tags with CSS in them then that could pose a significant problem.
Perhaps we could do: screen.logTestingPlaygroundURL(document.documentElement)
or something? That way you opt-into this behavior with the default being document.body
.
Wondering if using something like this https://pieroxy.net/blog/pages/lz-string/index.html would make it a bit shorter?
A problem I can see with this is we have a hard limit on the amount of stuff we can include in that URL (URLs have a limited length).
I'm writing some tests for a project I'm working on that mounts essentially the whole app, which results in the body alone being quite heavy, getPlaygroundUrl(document.body.innerHTML)
gives a URL of length 52277, whereas getPlaygroundUrl(document.documentElement.innerHTML)
gives a URL of length 68526 - so it is definitely larger with the head included, but they are somewhat comparable. Interestingly, even though the user experience of spitting out a URL taking up hundreds of lines in your terminal maybe isn't the best, both work! Although the styles don't exist in the former, and don't apply correctly in the latter. This is on Firefox 82.
This from the Chromium docs seems to suggest that if there is a limit, it's pretty huge, at least for modern browsers:
In general, the web platform does not have limits on the length of URLs (although 2^31 is a common limit). Chrome limits URLs to a maximum length of 2MB for practical reasons and to avoid causing denial-of-service problems in inter-process communication.
There does seem to be some advice out there on the internet that advises you stick to URLs / GET requests of 2,048 characters or shorter. I'm wondering if this is informed by limitations of specific browsers, or maybe even SEO concerns? If so, we should be able to ignore this.
Wondering if using something like this https://pieroxy.net/blog/pages/lz-string/index.html would make it a bit shorter?
Looks like that's already being used:
https://github.com/testing-library/dom-testing-library/blob/f627ade1d8169db6113181a3893c847c10fa3ee2/src/screen.js#L1
Perhaps we could do: screen.logTestingPlaygroundURL(document.documentElement) or something? That way you opt-into this behavior with the default being document.body.
Interesting, I didn't see that it could already accept an element. Maybe the issue in this repo isn't neccessary, and only changes in testing-playground are needed. Maybe it could attempt to detect if head and body are present in the decoded markup, and handle things differently if so.
cc @smeijer
We indeed already use lz-string
for compression. So there is not much we can do about the max length of the url.
Regarding that length, if the issue is indeed a legacy thing, then we could ignore it. As most developers use the latest version of Chrome and/or Firefox anyway. I don't ignore it for testing-playground itself. But the devs that use dom-testing-library to print the playground url, are a different audience. So I don't foresee issues there if it's really a legacy thing. We would need to confirm and decide if we want to ignore legacy browsers (sounds acceptable to me).
About including the styling, this doesn't require any changes in Testing-Playground itself. The <style>
tag from the HEAD, can simply be prepended to the markup. See for example: https://testing-playground.com/#markup=DwZwLgngNgpgfAKAHQDMCqBbFAPAXgAgG8EBjAeyjICcAufKmAEwG4EBfBYAenGnk8YBLAG6JgQ4fhJQAhiBABeAEQgSAWgBGjFACEA7gEV86LHiVwAkvhkZr+XrEb4wAC0EA7AObcJYrr6A
This same thing would be possible for included <script>
tags, if required. But please let me know if I'm missing something. I'm happy to adjust the playground to support your needs.
Back to the URL length, an alternative option is to use a POST request and submit the markup to the server in return for a shorter url. This has some benefits (shorter url, no max url length problems), but you'd need to realize that it means that your code is stored on a server. We could also make that optional instead. (Data is saved as github gist).
screen.createPlayground();
An example request to make such an url:
await fetch('https://testing-playground.com/api/gist', {
method: 'POST',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({
files: {
'playground.json': { content: JSON.stringify({}, null, 2) },
'source.html': { content: '<!-- markup here -->' },
'source.js': { content: '// query here' },
},
}),
});
All three files are required, even if they're empty. That's simply because this api is currently only internally used. I can make them optional if it's an issue.
The request above returns:
{
"id": "8e1abf322151eae15e67fb5567f651f4",
"version": "b417598b466be9f77cbb992b3d690ab151f43cd7",
"url": "https://testing-playground.com/gist/8e1abf322151eae15e67fb5567f651f4/b417598b466be9f77cbb992b3d690ab151f43cd7"
}
So that playground is available under:
https://testing-playground.com/gist/8e1abf322151eae15e67fb5567f651f4/b417598b466be9f77cbb992b3d690ab151f43cd7
And that's the URL that should then be logged to the terminal, and/or automatically opened.
In other words, there is currently no reason why testing-playground.com wouldn't be able to render styles. That being said, I have my concerns about automatically extracting styles.
- What if the user uses a mix of stylesheets and css-in-js? Will we include ALL style tags?
- What if it's A LOT? It does add noise to the markdown pane.
- Is it really important for debugging? (might be in case of
visibility: 'hidden'
)
screen.logTestingPlaygroundURL(document.documentElement)
this is working for me. Thanks