'How to unit test .ejs files that produced by Express server?
I have a simple http Express server that serves a couple of routes like home, about, news, etc.
For each of routes, I use res.render('some_ejs_file'), to render a html page with .ejs extension. each page has a .js file script, and I just wonder how can I render the .ejs files to run the proper js file and render the page to test it?
I installed the @testing-library and jest and here is my home.test.js file:
import '@testing-library/jest-dom/extend-expect'
import { JSDOM } from 'jsdom'
import fs from 'fs'
import path from 'path'
const html = fs.readFileSync(
path.resolve(__dirname, '../views/pages/index.ejs'),
'utf8'
)
let dom
let container
describe('Home page', () => {
beforeEach(() => {
dom = new JSDOM(html, { runScripts: 'dangerously' })
container = dom.window.document.body
})
test('should show 1', () => {
console.log('>>> ', container.querySelector('header'))
expect(container.querySelector('h1')).not.toBeNull()
expect(1).toBe(1)
})
})
But the issue is that when I querySelect something from container, it always returns null and I can't proceed in testing step. What am I doing wrong, and how can I get proper testing experience with .ejs composed markup files?
Here is my jest config file:
module.exports = {
clearMocks: true,
setupFilesAfterEnv: ['regenerator-runtime/runtime'],
testPathIgnorePatterns: ['/node_modules/'],
moduleFileExtensions: ['js', 'jsx', 'ejs', 'ejx'],
}
Solution 1:[1]
I found the solution. Because we need to run and serve .ejs to test, first we need to render the ejs file, after looking some solutions inside ejs package documentations, I figured out that I might be able to render the ejs file first by this function:
ejs.renderFile(filename, data, options, function(err, str){
// str => Rendered HTML string
});
As you can see it will give you a string of the ejs rendered file, then with that you can pass the result into JSDOM and you have your DOM to Interact with in your testing environment!
Here was the final solution that I came up with:
import moment from 'moment'
import '@testing-library/jest-dom/extend-expect'
import { JSDOM } from 'jsdom'
import fs from 'fs'
import path from 'path'
import ejs from 'ejs'
const targetFile = path.resolve(__dirname, '../views/pages/index.ejs')
ejs.renderFile(targetFile, function (err, str) {
if (str) {
let dom
let container
describe('Home page', () => {
beforeEach(() => {
dom = new JSDOM(str, { moment }, { runScripts: 'dangerously' })
container = dom.window.document.body
})
test('should show 1', () => {
console.log('>>> ', container.querySelector('h1').textContent)
expect(container.querySelector('h1')).not.toBeNull()
expect(1).toBe(1)
})
})
}
})
I am happy to hear if I'm doing some thing wrong!
Solution 2:[2]
Amdev did a great job (thank you) laying this out but I adjusted a little as Jest was failing to detect a test when the describe() and test() were nested. The following refactored code may help others.
import "@testing-library/jest-dom/extend-expect";
import path from "path";
import ejs from "ejs";
import { JSDOM } from "jsdom";
import fs from "fs";
const targetFile = path.resolve(__dirname, "../src/index.ejs");
describe("[ROOT]", () => {
test("should load header section", () => {
ejs.renderFile(targetFile, function (err, htmlString) {
if (err) {
console.log(err);
}
if (htmlString) {
let dom;
let container;
beforeEach(() => {
dom = new JSDOM(htmlString, {}, { runScripts: "dangerously" });
container = dom.window.document.body;
});
console.log(dom);
expect(getByText(/MY TEXT/i)).toBeInTheDocument();
}
});
});
});
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 | halfer |
| Solution 2 | Sigma VX |
