I am using jest, jsdom and testing-libray/dom to test this page (index.html). i expect paragraph to be "welcome" but i am getting empty string ("") because a page (index.html) is loading before javascript.
I would like to ask if there are other ways to do it. thanks.
this is how my code looks like.
index.html
<html>
<body>
<p data-testid="paragraph"></p>
<script type="text/javascript">
const p = document.querySelector("p");
p.textContent = "welcome";
</script>
</body>
</html>
index.test.js
const { getByTestId } = require("#testing-library/dom");
const { JSDOM } = require("jsdom");
require("#testing-library/jest-dom/extend-expect");
const path = require("path");
const fs = require("fs");
let dom;
let container;
const html = fs.readFileSync(path.join(__dirname, "./index.html"));
describe("index", () => {
beforeEach(() => {
dom = new JSDOM(html, { runScripts: "dangerously" });
container = dom.window.document.body;
});
it("should display welcome text", () => {
const pEl = getByTestId(container, "paragraph");
expect(pEl.textContent).toEqual("welcome");
});
});
screenshoot
enter image description here
thanks
Related
I want to click a button in a shadow DOM inside an iframe. Is there a way to do this?
<html>
<head></head>
<body>
<iframe class="iframe_1">
#document
<div class="shadow-root">
#shadow-root (open)
<div>
<button id="btn_1"></button>
<button id="btn_2"></button>
</div>
</iframe>
</body>
</body>
I did this:
const frameHandle = await page.$("iframe.iframe_1");
const frame = await frameHandle.contentFrame();
var button = await frame.querySelector(".shadow-root").shadowRoot.querySelector("button[id='btn_1']");
await button.click();
But got the following error:
Uncaught TypeError TypeError: frame.querySelector is not a function
I know why this error has occurred, but I can't come up with other ideas. Please teach me.
The error is telling you that you're trying to call frame.querySelector, but querySelector is not a function that exists on frame. DOMElement#querySelector is defined in the browser only, which you can access via a frame using an evaluate-family call.
For example, if you want to return an element, you can use evaluateHandle:
const button = await frame.evaluateHandle(() =>
document.querySelector(".shadow-root")
.shadowRoot
.querySelector("#btn_1")
);
Here's a minimal, complete example you can run and see in action on your provided DOM structure:
index.html:
<!DOCTYPE html>
<html><body>
<iframe class="iframe_1"></iframe>
<script>
const html = `<!DOCTYPE html>
<div class="shadow-root"></div>
<script>
const el = document.querySelector(".shadow-root");
const root = el.attachShadow({mode: "open"});
el.shadowRoot.innerHTML = \`
<button id="btn_1">A</button>
<button id="btn_2">B</button>
\`;
el.shadowRoot.querySelector("#btn_1").addEventListener("click", event => {
event.target.textContent = "clicked";
});
<\/script>
`;
const doc = document.querySelector("iframe").contentWindow.document;
doc.open();
doc.write(html);
doc.close();
</script>
</body></html>
index.js:
const fs = require("node:fs/promises");
const puppeteer = require("puppeteer"); // ^19.6.3
let browser;
(async () => {
browser = await puppeteer.launch();
const [page] = await browser.pages();
const html = (await fs.readFile("index.html")).toString();
await page.setContent(html);
const frameHandle = await page.$("iframe.iframe_1");
const frame = await frameHandle.contentFrame();
const button = await frame.evaluateHandle(() =>
document.querySelector(".shadow-root")
.shadowRoot
.querySelector("#btn_1")
);
await button.click();
const result = await button.evaluate(el => el.textContent);
console.log(result); // => clicked
})()
.catch(err => console.error(err))
.finally(() => browser?.close());
Basically I am trying to only give access to a certain page if a user has a certain item. After that is authenticated, the new page is only able to show basic HTML and CSS styling. The JavaScript does not seem to be loading at all... This is my index.html
const revealMsg = async () => {
var signature = await web3.eth.personal.sign("Message to sign", account)
console.log(signature)
var res = await fetch('/exclusive?signature=' + signature)
//console.log(res)
var body = await res.text()
//console.log(body);
if (body != 'FALSE') {
//console.log(body)
document.querySelector('html').innerHTML = body;
} else {
//alert you do not have item
alert("You do not have the item!");
}
}
This is my server.js
app.get('/exclusive', async (req, res) => {
isMember = false
var address = await web3.eth.accounts.recover("Message to sign", req.query.signature);
console.log(address)
var balanceOne = Number(await contractOne.methods.balanceOf(address).call())
var balanceTwo = Number(await contractTwo.methods.balanceOf(address).call())
console.log("Balance 1: ", balanceOne)
console.log("Balance 2: ", balanceTwo)
if(balanceOne > 0 || balanceTwo > 0){
isMember = true;
res.sendFile(path.join(__dirname, '/exclusive.html'))
}else{
res.send("FALSE")
}
})
And here is the exclusive page I am trying to test simple JS things
<!DOCTYPE html>
<html>
<head>
<title>Exclusive Page</title>
<script src="https://cdn.jsdelivr.net/npm/web3#latest/dist/web3.min.js"></script>
<style>
body {
background-color: red;
}
</style>
<h1>Hello World</h1>
<button onclick="clear()">Lost Tapes</button>
<button id="clear2">Clear2</button>
<script>
const clear = () => {
console.log('clear')
}
function clear2() {
console.log('clear2');
}
document.getElementById("clear2").onclick = clear2
</script>
</body>
</html>
This is the current snippet that is not running any of the Motoko scripts in edX when inserted onto a page.
All that is being parsed currently is the Html part.
Are the scripts pointing to the correct file locations or have I done something wrong during the upload process?
<div id="counter" class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-motoko hljs" data-lang="motoko">actor Counter {
var value = 0;
public func inc() : async Nat {
value += 1;
return value;
};
}</code></pre>
</div>
</div>
<!-- Start of dfinity Zendesk Widget script -->
<script id="ze-snippet" src="https://static.zdassets.com/ekr/snippet.js?key=53121947-c10a-484c-b99b-f89a9fb6f63e"> </script>
<!-- End of dfinity Zendesk Widget script -->
<script async type="text/javascript" src="https://courses.edx.org/asset-v1:DFINITY+IC001+3T2021a+type#asset+block#behavior.js"></script>
<script async type="text/javascript" src="https://courses.edx.org/asset-v1:DFINITY+IC001+3T2021a+type#asset+block#highlight.bundle.js"></script>
<script type="text/javascript" src="https://courses.edx.org/asset-v1:DFINITY+IC001+3T2021a+type#asset+block#run_repl.js"></script>
<script type="module">
import {CodeJar} from 'https://cdn.jsdelivr.net/npm/codejar#3.2.3/codejar.min.js';
import {withLineNumbers} from 'https://cdn.jsdelivr.net/npm/codejar#3.2.3/linenumbers.js';
window.CodeJar = CodeJar;
window.withLineNumbers = withLineNumbers;
</script>
<script type="module">
import {CodeJar} from 'https://medv.io/codejar/codejar.js'
</script>
<script type="text/javascript">
async function addPackage(name, repo, version, dir) {
const meta_url = `https://data.jsdelivr.com/v1/package/gh/${repo}#${version}/flat`;
const base_url = `https://cdn.jsdelivr.net/gh/${repo}#${version}`;
const response = await fetch(meta_url);
const json = await response.json()
const promises = [];
const fetchedFiles = [];
for (const f of json.files) {
if (f.name.startsWith(`/${dir}/`) && /\.mo$/.test(f.name)) {
const promise = (async () => {
const content = await (await fetch(base_url + f.name)).text();
const stripped = name + f.name.slice(dir.length + 1);
fetchedFiles.push(stripped);
Motoko.saveFile(stripped, content);
})();
promises.push(promise);
}
}
Promise.all(promises).then(() => {
Motoko.addPackage(name, name + '/');
console.log(`Loaded motoko library "${name}"`);
changeCodeBlock(); // from run_repl.js
});
}
function loadBase() {
addPackage('base', 'dfinity/motoko-base', 'dfx-0.8.4', 'src');
}
</script>
<script async src="https://courses.edx.org/asset-v1:DFINITY+IC001+3T2021a+type#asset+block#moc-interpreter-0.6.20.js" onload="loadBase()"></script>
after looking through your code there's a few missing pieces that may solve the problem.
The hightjs script is missing, which you can either attach to the head or body. You can choose to include their stylesheet or not.
https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/default.min.css
https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/highlight.min.js
The run_repl here (https://courses.edx.org/asset-v1:DFINITY+IC001+3T2021a+type#asset+block#run_repl.js) has unexpected characters (backslashes) such that the file is not truly working. Please copy and replicate from here: https://github.com/dfinity/antora-sdk/blob/master/src/js/vendor/run_repl.js
There's some styling added inside Dfinity's website, which has been referenced. I've pulled it into a stylesheet on this replit project. Take a look!
https://replit.com/#Sue-AnnAnn/Motoko-highlight#index.html
There is an easier solution now!
https://embed.smartcontracts.org/motoko/g/3oBbKveNbudpGgKMb2A5wADMcv3U6CDvxfjKMvASfcmkuXEk9j7UtFCn2DpHrUVJ3dSJYEMu2bW54vZRiPhYk4MDgdXkQhHwt1HhmcLi3GpCowBeaYus4BUpMZNDMLKezqBwcMg7EXFbVvNYR5xp57dViryE9uawnFjkuZacyor5jp?lines=10
Copy the iframe code and embed it into a raw HTML page on EDX.
I was following this well known tutorial about adding react to a website. I was trying to replace my actual login div which contains many elements like form, buttons, spans, etc. However when I was setting up a controlled input component via React.useState, this leaded to the error reported in title.
I'll try to reproduce the problem with this simple snippet.
var LoginBox = function LoginBox(props) {
var rusername = React.useState('');
var username = rusername[0];
var setUsername = rusername[1];
var rpassword = React.useState('');
var password = rpassword[0];
var setPassword = rpassword[1];
var style = { width: 180 };
var onLogin = function onLogin() {
console.log('login');
};
var onLogout = function onLogout() {
console.log('logout');
};
return React.createElement('div', null, 'loginbox');
};
var domContainer = document.querySelector('#loginBoxContainer');
ReactDOM.render(LoginBox(), domContainer);
<html>
<head>
<script src="https://unpkg.com/react#17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#17/umd/react-dom.development.js" crossorigin></script>
</head>
<body>
<div>other html</div>
<div id="loginBoxContainer"></div>
</body>
</html>
Why is this error raised?
What can I do to add react to parts of my website without having to rewrite all of it in react?
Instead of calling LoginBox() you need to use React.createElement(LoginBox)
var LoginBox = function LoginBox(props) {
var rusername = React.useState('');
var username = rusername[0];
var setUsername = rusername[1];
var rpassword = React.useState('');
var password = rpassword[0];
var setPassword = rpassword[1];
var style = { width: 180 };
var onLogin = function onLogin() {
console.log('login');
};
var onLogout = function onLogout() {
console.log('logout');
};
return React.createElement('div', null, 'loginbox');
};
var domContainer = document.querySelector('#loginBoxContainer');
ReactDOM.render(React.createElement(LoginBox), domContainer);
<html>
<head>
<script src="https://unpkg.com/react#17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#17/umd/react-dom.development.js" crossorigin></script>
</head>
<body>
<div>other html</div>
<div id="loginBoxContainer"></div>
</body>
</html>
try this:
var LoginBox = function LoginBox(props) {
var [username, setUsername] = React.useState("");
var [password, setPassword] = React.useState("");
return React.createElement("div", null, "loginbox");
};
window.addEventListener('DOMContentLoaded', (event) => {
ReactDOM.render(
React.createElement(LoginBox, null),
document.getElementById('loginBoxContainer')
);
});
live demo here: https://www.w3schools.com/code/tryit.asp?filename=GNPVHJEXE03P
Trying to use wkhtmltox to turn an HTML file to an image:
./server.js
const express = require('express');
const fs = require('fs');
const wkhtmltox = require('wkhtmltox');
const app = express();
const converter = new wkhtmltox();
app.get('/tagslegend.png', (request, response) => {
response.status(200).type('png');
converter.image(fs.createReadStream('tagslegend.html'), { format: "png" }).pipe(response);
});
var listener = app.listen(process.env.PORT, function () {
console.log('App listening on port ' + listener.address().port);
});
And ./tagslegend.html:
<!doctype html>
<html>
<body>
<dl>
<dt>中文</dt><dd>In mandarin language.</dd>
</dl>
</body>
</html>
I'm expecting back an image of the above HTML, e.g. (how my browser would render it):
Instead I get back this:
How can I render that HTML to a png dynamically with the correct chinese characters and serve it to clients?
Add
<meta charset="utf-8">
to the <head> of the HTML document