Use let or const to avoid scope issues and hoisting
var assert = require('node:assert')
1'use strict'23var assert = require('node:assert')4var express = require('..');5var path = require('node:path')6var tmpl = require('./support/tmpl');78describe('app', function(){9 describe('.render(name, fn)', function(){10 it('should support absolute paths', function(done){11 var app = createApp();1213 app.locals.user = { name: 'tobi' };1415 app.render(path.join(__dirname, 'fixtures', 'user.tmpl'), function (err, str) {16 if (err) return done(err);17 assert.strictEqual(str, '<p>tobi</p>')18 done();19 })20 })2122 it('should support absolute paths with "view engine"', function(done){23 var app = createApp();2425 app.set('view engine', 'tmpl');26 app.locals.user = { name: 'tobi' };2728 app.render(path.join(__dirname, 'fixtures', 'user'), function (err, str) {29 if (err) return done(err);30 assert.strictEqual(str, '<p>tobi</p>')31 done();32 })33 })3435 it('should expose app.locals', function(done){36 var app = createApp();3738 app.set('views', path.join(__dirname, 'fixtures'))39 app.locals.user = { name: 'tobi' };4041 app.render('user.tmpl', function (err, str) {42 if (err) return done(err);43 assert.strictEqual(str, '<p>tobi</p>')44 done();45 })46 })4748 it('should support index.<engine>', function(done){49 var app = createApp();5051 app.set('views', path.join(__dirname, 'fixtures'))52 app.set('view engine', 'tmpl');5354 app.render('blog/post', function (err, str) {55 if (err) return done(err);56 assert.strictEqual(str, '<h1>blog post</h1>')57 done();58 })59 })6061 it('should handle render error throws', function(done){62 var app = express();6364 function View(name, options){65 this.name = name;66 this.path = 'fale';67 }6869 View.prototype.render = function(options, fn){70 throw new Error('err!');71 };7273 app.set('view', View);7475 app.render('something', function(err, str){76 assert.ok(err)77 assert.strictEqual(err.message, 'err!')78 done();79 })80 })8182 describe('when the file does not exist', function(){83 it('should provide a helpful error', function(done){84 var app = createApp();8586 app.set('views', path.join(__dirname, 'fixtures'))87 app.render('rawr.tmpl', function (err) {88 assert.ok(err)89 assert.equal(err.message, 'Failed to lookup view "rawr.tmpl" in views directory "' + path.join(__dirname, 'fixtures') + '"')90 done();91 });92 })93 })9495 describe('when an error occurs', function(){96 it('should invoke the callback', function(done){97 var app = createApp();9899 app.set('views', path.join(__dirname, 'fixtures'))100101 app.render('user.tmpl', function (err) {102 assert.ok(err)103 assert.equal(err.name, 'RenderError')104 done()105 })106 })107 })108109 describe('when an extension is given', function(){110 it('should render the template', function(done){111 var app = createApp();112113 app.set('views', path.join(__dirname, 'fixtures'))114115 app.render('email.tmpl', function (err, str) {116 if (err) return done(err);117 assert.strictEqual(str, '<p>This is an email</p>')118 done();119 })120 })121 })122123 describe('when "view engine" is given', function(){124 it('should render the template', function(done){125 var app = createApp();126127 app.set('view engine', 'tmpl');128 app.set('views', path.join(__dirname, 'fixtures'))129130 app.render('email', function(err, str){131 if (err) return done(err);132 assert.strictEqual(str, '<p>This is an email</p>')133 done();134 })135 })136 })137138 describe('when "views" is given', function(){139 it('should lookup the file in the path', function(done){140 var app = createApp();141142 app.set('views', path.join(__dirname, 'fixtures', 'default_layout'))143 app.locals.user = { name: 'tobi' };144145 app.render('user.tmpl', function (err, str) {146 if (err) return done(err);147 assert.strictEqual(str, '<p>tobi</p>')148 done();149 })150 })151152 describe('when array of paths', function(){153 it('should lookup the file in the path', function(done){154 var app = createApp();155 var views = [156 path.join(__dirname, 'fixtures', 'local_layout'),157 path.join(__dirname, 'fixtures', 'default_layout')158 ]159160 app.set('views', views);161 app.locals.user = { name: 'tobi' };162163 app.render('user.tmpl', function (err, str) {164 if (err) return done(err);165 assert.strictEqual(str, '<span>tobi</span>')166 done();167 })168 })169170 it('should lookup in later paths until found', function(done){171 var app = createApp();172 var views = [173 path.join(__dirname, 'fixtures', 'local_layout'),174 path.join(__dirname, 'fixtures', 'default_layout')175 ]176177 app.set('views', views);178 app.locals.name = 'tobi';179180 app.render('name.tmpl', function (err, str) {181 if (err) return done(err);182 assert.strictEqual(str, '<p>tobi</p>')183 done();184 })185 })186187 it('should error if file does not exist', function(done){188 var app = createApp();189 var views = [190 path.join(__dirname, 'fixtures', 'local_layout'),191 path.join(__dirname, 'fixtures', 'default_layout')192 ]193194 app.set('views', views);195 app.locals.name = 'tobi';196197 app.render('pet.tmpl', function (err, str) {198 assert.ok(err)199 assert.equal(err.message, 'Failed to lookup view "pet.tmpl" in views directories "' + views[0] + '" or "' + views[1] + '"')200 done();201 })202 })203 })204 })205206 describe('when a "view" constructor is given', function(){207 it('should create an instance of it', function(done){208 var app = express();209210 function View(name, options){211 this.name = name;212 this.path = 'path is required by application.js as a signal of success even though it is not used there.';213 }214215 View.prototype.render = function(options, fn){216 fn(null, 'abstract engine');217 };218219 app.set('view', View);220221 app.render('something', function(err, str){222 if (err) return done(err);223 assert.strictEqual(str, 'abstract engine')224 done();225 })226 })227 })228229 describe('caching', function(){230 it('should always lookup view without cache', function(done){231 var app = express();232 var count = 0;233234 function View(name, options){235 this.name = name;236 this.path = 'fake';237 count++;238 }239240 View.prototype.render = function(options, fn){241 fn(null, 'abstract engine');242 };243244 app.set('view cache', false);245 app.set('view', View);246247 app.render('something', function(err, str){248 if (err) return done(err);249 assert.strictEqual(count, 1)250 assert.strictEqual(str, 'abstract engine')251 app.render('something', function(err, str){252 if (err) return done(err);253 assert.strictEqual(count, 2)254 assert.strictEqual(str, 'abstract engine')255 done();256 })257 })258 })259260 it('should cache with "view cache" setting', function(done){261 var app = express();262 var count = 0;263264 function View(name, options){265 this.name = name;266 this.path = 'fake';267 count++;268 }269270 View.prototype.render = function(options, fn){271 fn(null, 'abstract engine');272 };273274 app.set('view cache', true);275 app.set('view', View);276277 app.render('something', function(err, str){278 if (err) return done(err);279 assert.strictEqual(count, 1)280 assert.strictEqual(str, 'abstract engine')281 app.render('something', function(err, str){282 if (err) return done(err);283 assert.strictEqual(count, 1)284 assert.strictEqual(str, 'abstract engine')285 done();286 })287 })288 })289 })290 })291292 describe('.render(name, options, fn)', function(){293 it('should render the template', function(done){294 var app = createApp();295296 app.set('views', path.join(__dirname, 'fixtures'))297298 var user = { name: 'tobi' };299300 app.render('user.tmpl', { user: user }, function (err, str) {301 if (err) return done(err);302 assert.strictEqual(str, '<p>tobi</p>')303 done();304 })305 })306307 it('should expose app.locals', function(done){308 var app = createApp();309310 app.set('views', path.join(__dirname, 'fixtures'))311 app.locals.user = { name: 'tobi' };312313 app.render('user.tmpl', {}, function (err, str) {314 if (err) return done(err);315 assert.strictEqual(str, '<p>tobi</p>')316 done();317 })318 })319320 it('should give precedence to app.render() locals', function(done){321 var app = createApp();322323 app.set('views', path.join(__dirname, 'fixtures'))324 app.locals.user = { name: 'tobi' };325 var jane = { name: 'jane' };326327 app.render('user.tmpl', { user: jane }, function (err, str) {328 if (err) return done(err);329 assert.strictEqual(str, '<p>jane</p>')330 done();331 })332 })333334 it('should accept null or undefined options', function (done) {335 var app = createApp()336337 app.set('views', path.join(__dirname, 'fixtures'))338 app.locals.user = { name: 'tobi' }339340 app.render('user.tmpl', null, function (err, str) {341 if (err) return done(err);342 assert.strictEqual(str, '<p>tobi</p>')343344 app.render('user.tmpl', undefined, function (err2, str2) {345 if (err2) return done(err2);346 assert.strictEqual(str2, '<p>tobi</p>')347 done()348 })349 })350 })351352 describe('caching', function(){353 it('should cache with cache option', function(done){354 var app = express();355 var count = 0;356357 function View(name, options){358 this.name = name;359 this.path = 'fake';360 count++;361 }362363 View.prototype.render = function(options, fn){364 fn(null, 'abstract engine');365 };366367 app.set('view cache', false);368 app.set('view', View);369370 app.render('something', {cache: true}, function(err, str){371 if (err) return done(err);372 assert.strictEqual(count, 1)373 assert.strictEqual(str, 'abstract engine')374 app.render('something', {cache: true}, function(err, str){375 if (err) return done(err);376 assert.strictEqual(count, 1)377 assert.strictEqual(str, 'abstract engine')378 done();379 })380 })381 })382 })383 })384})385386function createApp() {387 var app = express();388389 app.engine('.tmpl', tmpl);390391 return app;392}
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.