'Can we directly unit test HTML embedded JavaScript functions?
Suppose we have a webpage with embedded JavaScript as in index.html
as follows:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta charset="utf-8" />
<title>Cypress - Testing the Tester</title>
<script>/*<![CDATA[*/
function foo() {
return "bar";
}
function outputMessage(message) {
document.querySelector("output").innerHTML += message + "<br />";
}
window.addEventListener("pageshow", function(){
outputMessage(foo());
});
/*]]>*/</script>
</head>
<body>
<h1>Cypress - Testing the Tester</h1>
<output></output>
</body>
</html>
On page show (e.g. load) this inserts the string "bar" inside <output></output>
.
If my_cypress_spec.js
is:
describe('The Home Page Tests', () => {
it('Test HTML embedded JavaScript function', () => {
// Assumes, e.g. "baseUrl": "http://127.0.0.1:5500" set in cypress.json
cy.visit('index.html');
expect(foo()).to.equal("bar");
});
});
then in the Cypress test runner I get a "ReferenceError ... foo is not defined". That is, it appears Cypress doesn't recognize the foo()
function.
Is there a way for Cypress to directly unit test the foo()
function? That is, without relying on ES6/ES2015 export/imports (where the above is refactored to put foo()
in its own JavaScript file where it is exported and my_cypress_spec.js
imports this)?
Attempting @Fody's suggestion my my_cypress_spec.js
becomes:
describe('The Home Page Tests', () => {
it('Test HTML embedded JavaScript function', () => {
// Assumes, e.g. "baseUrl": "http://127.0.0.1:5500" set in cypress.json
cy.visit('index.html');
cy.window().then(win => {
expect(win.foo()).to.eq('bar');
});
});
});
and I get the error "TypeError ... win.foo is not a function".
Solution 1:[1]
Fody's answer works. So, in full my_cypress_spec.js
can become something like:
describe('The Home Page Tests', () => {
it('Test HTML embedded JavaScript function', () => {
// Assumes, e.g. "baseUrl": "http://127.0.0.1:5500" set in cypress.json
cy.visit('index.html');
cy.window().then(win => {
expect(win.foo()).to.eq('bar');
});
});
});
However, the reason I was getting a "TypeError ... win.foo is not a function" was because in my index.html
on my machine (not as originally posted above) I had an opening <script type="module">
. Changing that back to <script>
made the test pass.
So for completeness I'll tag this as The Answer while noting the insights come from @Fody and @jonrsharpe.
Solution 2:[2]
I'm not sure how well this will apply if you are using a more complex app, e.g created with Angular or React. Those frameworks have specialized test harnesses for unit testing.
For the vanilla JS example you gave, it's quite easy since foo()
gets attached to the window of the AUT.
cy.window().then(win => {
expect(win.foo()).to.eq('bar')
})
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | John Bentley |
Solution 2 |