├── example
├── view
│ ├── user.oc.html
│ ├── async.html
│ ├── content.html
│ ├── content.noext.html
│ ├── user.html
│ ├── template.html
│ └── template.oc.html
├── app.js
└── app-with-custom-fs-module.js
├── .eslintrc
├── .travis.yml
├── .editorconfig
├── .nycrc
├── .gitignore
├── LICENSE
├── package.json
├── test
├── write-response.test.js
└── koa-ejs.test.js
├── README.md
├── index.js
└── HISTORY.md
/example/view/user.oc.html:
--------------------------------------------------------------------------------
1 | = user.name ?>
2 |
--------------------------------------------------------------------------------
/example/view/async.html:
--------------------------------------------------------------------------------
1 | <%= await sayHello('Jack') %>
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "standard",
3 | "env": {
4 | "mocha": true
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 12
4 | - 14
5 | - 16
6 | script:
7 | - npm run ci
8 |
--------------------------------------------------------------------------------
/example/view/content.html:
--------------------------------------------------------------------------------
1 |
2 |
request ip is: <%= ip %>
3 | <%- include('user.html') -%>
4 |
5 |
--------------------------------------------------------------------------------
/example/view/content.noext.html:
--------------------------------------------------------------------------------
1 |
2 |
request ip is: <%= ip %>
3 | <%- include ('user') -%>
4 |
5 |
--------------------------------------------------------------------------------
/example/view/user.html:
--------------------------------------------------------------------------------
1 |
2 | <% users.forEach(function (user) {%>
3 | - <%= user.name %>
4 | <% })%>
5 |
6 |
--------------------------------------------------------------------------------
/example/view/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | koa ejs
4 |
5 |
6 | koa ejs
7 | <%- body %>
8 |
9 |
10 |
--------------------------------------------------------------------------------
/example/view/template.oc.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | koa ejs
4 |
5 |
6 | koa ejs
7 | - body ?>
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/.nycrc:
--------------------------------------------------------------------------------
1 | {
2 | "all": false,
3 | "exclude": [
4 | "**/*.test.js",
5 | "example"
6 | ],
7 | "reporter": [
8 | "text-lcov",
9 | "text",
10 | "lcov"
11 | ],
12 | "report-dir": "./coverage",
13 | "temp-dir": "./.nyc_output"
14 | }
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS #
2 | ###################
3 | .DS_Store
4 | .idea
5 | Thumbs.db
6 | tmp
7 | temp
8 |
9 |
10 | # Node.js #
11 | ###################
12 | node_modules
13 | package-lock.json
14 | yarn.lock
15 |
16 |
17 | # NYC #
18 | ###################
19 | coverage
20 | .nyc_output
21 |
--------------------------------------------------------------------------------
/example/app.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * @koa/ejs - example/app.js
3 | *
4 | * Copyright(c) 2017 dead_horse
5 | * MIT Licensed
6 | */
7 |
8 | 'use strict'
9 |
10 | /**
11 | * Module dependencies.
12 | */
13 |
14 | const Koa = require('koa')
15 | const render = require('..')
16 | const path = require('path')
17 |
18 | const app = new Koa()
19 |
20 | render(app, {
21 | root: path.join(__dirname, 'view'),
22 | layout: 'template',
23 | viewExt: 'html',
24 | cache: false,
25 | debug: false
26 | })
27 |
28 | app
29 | .use(function (ctx, next) {
30 | ctx.state = ctx.state || {}
31 | ctx.state.now = new Date()
32 | ctx.state.ip = ctx.ip
33 | ctx.state.version = '2.0.0'
34 | return next()
35 | })
36 | .use(async function (ctx) {
37 | const users = [{ name: 'Dead Horse' }, { name: 'Imed Jaberi' }, { name: 'Tom' }]
38 | await ctx.render('content', { users })
39 | })
40 |
41 | if (process.env.NODE_ENV === 'test') {
42 | module.exports = app.callback()
43 | } else {
44 | app.listen(7001)
45 | console.log('open http://localhost:7001')
46 | }
47 |
48 | app.on('error', function (err) {
49 | console.log(err.stack)
50 | })
51 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright(c) 2017 dead_horse
4 | Copyright(c) 2021-2022 3imed-jaberi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy of
7 | this software and associated documentation files (the "Software"), to deal in
8 | the Software without restriction, including without limitation the rights to
9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10 | the Software, and to permit persons to whom the Software is furnished to do so,
11 | subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/example/app-with-custom-fs-module.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * koa-ejs - example/app-with-custom-fs-module
3 | *
4 | * Copyright(c) 2022 3imed-jaberi
5 | * MIT Licensed
6 | */
7 |
8 | 'use strict'
9 |
10 | /**
11 | * Module dependencies.
12 | */
13 |
14 | const Koa = require('koa')
15 | const render = require('..')
16 | const path = require('path')
17 |
18 | const app = new Koa()
19 |
20 | render(app, {
21 | root: path.join(__dirname, 'view'),
22 | fs: require('mz/fs'),
23 | layout: 'template',
24 | viewExt: 'html',
25 | cache: false,
26 | debug: false
27 | })
28 |
29 | app
30 | .use(function (ctx, next) {
31 | ctx.state = ctx.state || {}
32 | ctx.state.now = new Date()
33 | ctx.state.ip = ctx.ip
34 | ctx.state.version = '2.0.0'
35 | return next()
36 | })
37 | .use(async function (ctx) {
38 | const users = [{ name: 'Dead Horse' }, { name: 'Imed Jaberi' }, { name: 'Tom' }]
39 | await ctx.render('content', { users })
40 | })
41 |
42 | if (process.env.NODE_ENV === 'test') {
43 | module.exports = app.callback()
44 | } else {
45 | app.listen(7001)
46 | console.log('open http://localhost:7001')
47 | }
48 |
49 | app.on('error', function (err) {
50 | console.log(err.stack)
51 | })
52 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@koa/ejs",
3 | "version": "5.1.0",
4 | "description": "ejs render middleware for Koa.js",
5 | "main": "index.js",
6 | "files": [
7 | "index.js"
8 | ],
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/koajs/ejs.git"
12 | },
13 | "scripts": {
14 | "lint": "eslint .",
15 | "pretest": "npm run lint",
16 | "test": "cross-env NODE_ENV=test mocha --exit --reporter spec --timeout 5000 --require should test/*.test.js",
17 | "precoverage": "rimraf .nyc_output coverage",
18 | "coverage": "nyc npm run test",
19 | "ci": "npm run coverage"
20 | },
21 | "keywords": [
22 | "koa",
23 | "middleware",
24 | "render",
25 | "ejs",
26 | "view",
27 | "template-engine"
28 | ],
29 | "author": {
30 | "name": "dead_horse",
31 | "email": "dead_horse@qq.com",
32 | "url": "http://deadhorse.me"
33 | },
34 | "contributors": [
35 | {
36 | "name": "Imed Jaberi",
37 | "email": "imed-jaberi@outlook.com",
38 | "url": "https://www.3imed-jaberi.com"
39 | }
40 | ],
41 | "license": "MIT",
42 | "dependencies": {
43 | "debug": "^4.3.4",
44 | "ejs": "^3.1.8"
45 | },
46 | "devDependencies": {
47 | "cross-env": "^7.0.3",
48 | "eslint": "^7.30.0",
49 | "eslint-config-standard": "^16.0.3",
50 | "eslint-plugin-import": "^2.23.4",
51 | "eslint-plugin-node": "^11.1.0",
52 | "eslint-plugin-promise": "^5.1.0",
53 | "eslint-plugin-standard": "^5.0.0",
54 | "koa": "^2.13.4",
55 | "mocha": "^10.0.0",
56 | "mz": "^2.7.0",
57 | "nyc": "^15.1.0",
58 | "should": "^13.2.3",
59 | "supertest": "^6.2.4"
60 | },
61 | "engine": {
62 | "node": ">= 12"
63 | },
64 | "bugs": {
65 | "url": "https://github.com/koajs/ejs/issues"
66 | },
67 | "homepage": "https://github.com/koajs/ejs"
68 | }
69 |
--------------------------------------------------------------------------------
/test/write-response.test.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * @koa/ejs - test/koa/ejs.test.js
3 | * Copyright(c) 2017 dead_horse
4 | * MIT Licensed
5 | */
6 |
7 | 'use strict'
8 |
9 | /**
10 | * Module dependencies.
11 | */
12 |
13 | const render = require('..')
14 | const request = require('supertest')
15 | const Koa = require('koa')
16 |
17 | describe('test/write-response.test.js', function () {
18 | describe('writeResp option', function () {
19 | it('should return html with default configuration and writeResp option = false', function (done) {
20 | const app = new Koa()
21 | render(app, {
22 | root: 'example/view',
23 | layout: 'template.oc',
24 | viewExt: 'html',
25 | delimiter: '?'
26 | })
27 |
28 | app.use(async function (ctx, next) {
29 | const html = await ctx.render('user.oc', {
30 | user: { name: 'Zed Gu' },
31 | writeResp: false
32 | })
33 |
34 | ctx.type = 'html'
35 | ctx.body = html
36 | })
37 |
38 | request(app.callback())
39 | .get('/')
40 | .expect(200)
41 | .expect('content-type', 'text/html; charset=utf-8')
42 | .expect(/Zed Gu/, done)
43 | })
44 |
45 | it('should return html with configuration writeResp = false', function (done) {
46 | const app = new Koa()
47 | render(app, {
48 | root: 'example/view',
49 | layout: 'template.oc',
50 | viewExt: 'html',
51 | delimiter: '?',
52 | writeResp: false
53 | })
54 |
55 | app.use(async function (ctx) {
56 | const html = await ctx.render('user.oc', {
57 | user: { name: 'Zed Gu' }
58 | })
59 |
60 | ctx.type = 'html'
61 | ctx.body = html
62 | })
63 |
64 | request(app.callback())
65 | .get('/')
66 | .expect(200)
67 | .expect('content-type', 'text/html; charset=utf-8')
68 | .expect(/Zed Gu/, done)
69 | })
70 | })
71 | })
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # @koa/ejs
2 |
3 | > Koa ejs view render middleware. support all feature of [ejs](https://github.com/mde/ejs).
4 |
5 | [](http://travis-ci.org/koajs/ejs)
6 |
7 | [](https://nodei.co/npm/@koa/ejs/)
8 |
9 | ## Usage
10 |
11 | ### Example
12 |
13 | ```js
14 | const Koa = require("koa");
15 | const render = require("@koa/ejs");
16 | const path = require("path");
17 |
18 | const app = new Koa();
19 | render(app, {
20 | root: path.join(__dirname, "view"),
21 | layout: "template",
22 | viewExt: "html",
23 | cache: false,
24 | debug: true,
25 | });
26 |
27 | app.use(async function (ctx) {
28 | await ctx.render("user");
29 | });
30 |
31 | app.listen(7001);
32 | ```
33 |
34 | Or you can checkout the [example](https://github.com/koajs/ejs/tree/master/example).
35 |
36 | ### Settings
37 |
38 | - root: view root directory.
39 | - fs: file system module with same Node.js fs interface (default `Node.js fs module`).
40 | - layout: global layout file, default is `layout`, set `false` to disable layout.
41 | - viewExt: view file extension (default `html`).
42 | - cache: cache compiled templates (default `true`).
43 | - debug: debug flag (default `false`).
44 | - delimiter: character to use with angle brackets for open / close (default `%`).
45 | - async: When true, EJS will use an async function for rendering. Depends on async/await support in the JS runtime.
46 | - outputFunctionName: Set to a string (e.g., 'echo' or 'print') for a function to print output inside scriptlet tags.
47 |
48 | ### Layouts
49 |
50 | `@koa/ejs` supports layouts. The default layout file is `layout`. If you want to change default layout file, use `settings.layout`. Also you can specify layout by `options.layout` in `await ctx.render`.
51 | Also you can set `layout = false` to disable the layout.
52 |
53 | ```
54 |
55 |
56 | koa ejs
57 |
58 |
59 | koa ejs
60 | <%- body %>
61 |
62 |
63 | ```
64 |
65 | ### Include
66 |
67 | Supports ejs includes.
68 |
69 | ```
70 |
71 | <%- include ('user.html') -%>
72 |
73 | ```
74 |
75 | ### State
76 |
77 | Support [`ctx.state` in koa](https://github.com/koajs/koa/blob/master/docs/api/context.md#ctxstate).
78 |
79 |
80 | ### TypeScript
81 |
82 | If you're project based on TypeScript, we recommend using [`@types/koa-ejs`](https://www.npmjs.com/package/@types/koa-ejs) until we start supporting it in the upcoming releases.
83 |
84 | ## Licences
85 |
86 | [(The MIT License)](LICENSE)
87 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * @koa/ejs
3 | *
4 | * Copyright(c) 2017 dead_horse
5 | * Copyright(c) 2021-2022 3imed-jaberi
6 | * MIT Licensed
7 | */
8 |
9 | 'use strict'
10 |
11 | /**
12 | * Module dependencies.
13 | */
14 |
15 | const ejs = require('ejs')
16 | const path = require('path')
17 | const debug = require('debug')('@koa/ejs')
18 |
19 | /**
20 | * Temp assigned for override later
21 | */
22 | const parentResolveInclude = ejs.resolveInclude
23 |
24 | /**
25 | * default render options
26 | * @type {Object}
27 | */
28 | const defaultSettings = {
29 | cache: true,
30 | layout: 'layout',
31 | viewExt: 'html',
32 | locals: {},
33 | compileDebug: false,
34 | debug: false,
35 | writeResp: true,
36 | async: false
37 | }
38 |
39 | exports = module.exports = koaEjs
40 |
41 | /**
42 | * set app.context.render
43 | *
44 | * usage:
45 | * ```
46 | * await ctx.render('user', {name: 'dead_horse'});
47 | * ```
48 | * @param {Application} app koa application instance
49 | * @param {Object} settings user settings
50 | */
51 | function koaEjs (app, settings) {
52 | if (app.context.render) return
53 | if (!settings || !settings.root) throw new Error('settings.root required')
54 | settings.root = path.resolve(process.cwd(), settings.root)
55 | // cache the generate package
56 | const cache = {}
57 | settings = { ...defaultSettings, ...settings }
58 | settings.viewExt = settings.viewExt ? '.' + settings.viewExt.replace(/^\./, '') : ''
59 | settings.fs = settings.fs || require('fs/promises')
60 |
61 | // override `ejs` node_module `resolveInclude` function
62 | ejs.resolveInclude = function (name, filename, isDir) {
63 | if (!path.extname(name)) name += settings.viewExt
64 | return parentResolveInclude(name, filename, isDir)
65 | }
66 |
67 | /**
68 | * generate html with view name and options
69 | *
70 | * @param {String} view
71 | * @param {Object} options
72 | * @return {String} html
73 | */
74 | async function render (view, options) {
75 | view += settings.viewExt
76 | const viewPath = path.join(settings.root, view)
77 | debug(`render: ${viewPath}`)
78 | // get from cache
79 | if (settings.cache && cache[viewPath]) return cache[viewPath].call(options.scope, options)
80 |
81 | const tpl = await settings.fs.readFile(viewPath, 'utf8')
82 |
83 | const fn = ejs.compile(tpl, {
84 | filename: viewPath,
85 | _with: settings._with,
86 | compileDebug: settings.debug && settings.compileDebug,
87 | debug: settings.debug,
88 | delimiter: settings.delimiter,
89 | cache: settings.cache,
90 | async: settings.async,
91 | outputFunctionName: settings.outputFunctionName
92 | })
93 |
94 | if (settings.cache) cache[viewPath] = fn
95 |
96 | return fn.call(options.scope, options)
97 | }
98 |
99 | app.context.render = async function (view, _context) {
100 | const ctx = this
101 | const context = { ...ctx.state, ..._context }
102 | let html = await render(view, context)
103 |
104 | const layout = context.layout === false ? false : (context.layout || settings.layout)
105 | if (layout) {
106 | // if using layout
107 | context.body = html
108 | html = await render(layout, context)
109 | }
110 |
111 | const writeResp = context.writeResp === false ? false : (context.writeResp || settings.writeResp)
112 | if (writeResp) {
113 | // normal operation
114 | ctx.type = 'html'
115 | ctx.body = html
116 | }
117 |
118 | // only return the html
119 | return html
120 | }
121 | };
122 |
123 | /**
124 | * Expose ejs
125 | */
126 |
127 | exports.ejs = ejs
128 |
--------------------------------------------------------------------------------
/HISTORY.md:
--------------------------------------------------------------------------------
1 |
2 | # History
3 |
4 | **[PLEASE REFERENCE THE RELEASES TAB FOR THE LATEST CHANGES](https://github.com/koajs/ejs/releases)**
5 |
6 | 4.3.0 / 2019-12-04
7 | ==================
8 |
9 | **features**
10 | * [[`9bd7c37`](http://github.com/koajs/ejs/commit/9bd7c3790ccbba3d66e3bb9c4ab12ee020cf15fd)] - feat: support for outputFunctionName settings (#52) (Vojtěch Kozák <>)
11 |
12 | 4.2.1 / 2019-12-04
13 | ==================
14 |
15 | **others**
16 | * [[`129021b`](http://github.com/koajs/ejs/commit/129021bc9bae23910434ebba7a61b82b8245f6ea)] - chore: Move definition of resolveInclude() override out of closure (Anthony Howe <>)
17 |
18 | 4.2.0 / 2018-12-27
19 | ==================
20 |
21 | **features**
22 | * [[`ca1e00e`](http://github.com/koajs/ejs/commit/ca1e00ee388a759684ce949b9c089fa56f9c9de7)] - feat: upgrade ejs@2.6.1 and add `async` option (#47) (nswbmw <>)
23 |
24 | 4.1.2 / 2018-07-19
25 | ==================
26 |
27 | **fixes**
28 | * [[`245e1ee`](http://github.com/koajs/ejs/commit/245e1eeca515caebd2e5ffd6e1c3450ec159db4b)] - fix: cache includeFile (#45) (hyj1991 <<66cfat66@gmail.com>>)
29 |
30 | 4.1.1 / 2018-03-17
31 | ==================
32 |
33 | **fixes**
34 | * [[`f12513f`](http://github.com/koajs/ejs/commit/f12513fed78c6ee2cc02624dd861039c35a82737)] - fix: Fix Wrong function reference may cause 'Maxiumn call stack size exceeded' (Runrioter <>)
35 |
36 | **others**
37 | * [[`785f28a`](http://github.com/koajs/ejs/commit/785f28ab6c6fe6989bfd6741ef4803c0754d70e4)] - chore: add missing package.files (dead-horse <>)
38 | * [[`6babd1f`](http://github.com/koajs/ejs/commit/6babd1f58751ccf9e9c0fc1c99d4ebb3848719af)] - fix typo (#43) (Dan Bergren <>)
39 |
40 | 4.1.0 / 2017-06-27
41 | ==================
42 |
43 | * feat: Make `viewExt` option support `include` directive (#38)
44 | * correct the demo in the Readme
45 |
46 | 4.0.1 / 2017-06-25
47 | ==================
48 |
49 | * Fix `debug` setting bug (#37)
50 |
51 | 4.0.0 / 2017-02-28
52 | ==================
53 |
54 | * rewrite with async function and upgrade dependencies (#34)
55 |
56 | 3.0.0 / 2015-11-19
57 | ==================
58 |
59 | * Clean open/close settings
60 | * Switch to EJS v2
61 |
62 | 2.0.1 / 2015-04-22
63 | ==================
64 |
65 | * fix: contenxt not defined. fixes #18
66 |
67 | 2.0.0 / 2015-04-19
68 | ==================
69 |
70 | * add test for 0.12 and iojs
71 | * deps: ejs@1
72 | * refactor: remove locals
73 |
74 | 1.1.3 / 2014-12-18
75 | ==================
76 |
77 | * fix viewPath' bug, improve code
78 |
79 | 1.1.2 / 2014-08-30
80 | ==================
81 |
82 | * Merge pull request #8 from zedgu/master
83 | * for resolve to absolute path
84 |
85 | 1.1.1 / 2014-08-28
86 | ==================
87 |
88 | * Merge pull request #7 from lopezchr/clopez
89 | * adding write-response test suit
90 | * Addign no auto write body option
91 |
92 | 1.1.0 / 2014-08-12
93 | ==================
94 |
95 | * Merge pull request #6 from zedgu/master
96 | * [fix] open/close tag setting is not working
97 |
98 | 1.0.2 / 2014-07-14
99 | ==================
100 |
101 | * Merge pull request #5 from its-florida/master
102 | * Honor layout overrides in options.
103 |
104 | 1.0.1 / 2014-05-04
105 | ==================
106 |
107 | * updated default settings, fixes #3
108 |
109 | 1.0.0 / 2014-04-24
110 | ==================
111 |
112 | * refactor, close #2
113 |
114 | 0.0.3 / 2014-03-17
115 | ==================
116 |
117 | * update readme
118 | * support locals as generator
119 | * Merge pull request #1 from Pana/master
120 | * small edit
121 |
122 | 0.0.2 / 2014-03-11
123 | ==================
124 |
125 | * fix charset
126 | * fix typo
127 |
128 | 0.0.1 / 2014-02-25
129 | ==================
130 |
131 | * update readme
132 | * add test
133 | * rename koa-view to koa-ejs
134 | * rename koa-render to koa-view
135 | * add example
136 | * complete koa-render
137 | * Initial commit
138 |
--------------------------------------------------------------------------------
/test/koa-ejs.test.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * koa-ejs - test/koa-ejs.test.js
3 | * Copyright(c) 2017 dead_horse
4 | * MIT Licensed
5 | */
6 |
7 | 'use strict'
8 |
9 | /**
10 | * Module dependencies.
11 | */
12 |
13 | const render = require('..')
14 | const request = require('supertest')
15 | const Koa = require('koa')
16 |
17 | describe('test/koa-ejs.test.js', function () {
18 | describe('init()', function () {
19 | const app = new Koa()
20 | it('should throw error if no root', function () {
21 | (function () {
22 | render(app)
23 | }).should.throw('settings.root required');
24 |
25 | (function () {
26 | render(app, {})
27 | }).should.throw('settings.root required')
28 | })
29 |
30 | it('should init ok', function () {
31 | render(app, {
32 | root: __dirname,
33 | open: '{{',
34 | close: '}}'
35 | })
36 | // eslint-disable-next-line no-unused-expressions
37 | app.context.render.should.be.Function
38 | })
39 | })
40 |
41 | describe('server', function () {
42 | describe('with default node.js fs module', () => {
43 | it('should render page ok', function (done) {
44 | const app = require('../example/app')
45 | request(app)
46 | .get('/')
47 | .expect(200)
48 | .expect('content-type', 'text/html; charset=utf-8')
49 | .expect(/koa ejs<\/title>/)
50 | .expect(/Dead Horse/)
51 | .expect(/Imed Jaberi/, done)
52 | })
53 | it('should render page ok with async functions', function (done) {
54 | const app = new Koa()
55 | render(app, {
56 | root: 'example/view',
57 | viewExt: 'html',
58 | layout: false,
59 | async: true
60 | })
61 |
62 | app.use(async function (ctx) {
63 | await ctx.render('async', {
64 | async sayHello (name) {
65 | return `Hello, ${name}`
66 | }
67 | })
68 | })
69 | request(app.callback())
70 | .get('/')
71 | .expect(200)
72 | .expect('content-type', 'text/html; charset=utf-8')
73 | .expect(/Hello, Jack/, done)
74 | })
75 | it('should render page ok with custom open/close', function (done) {
76 | const app = new Koa()
77 | render(app, {
78 | root: 'example/view',
79 | layout: 'template.oc',
80 | viewExt: 'html',
81 | delimiter: '?'
82 | })
83 |
84 | app.use(async function (ctx) {
85 | await ctx.render('user.oc', {
86 | user: { name: 'Zed Gu' }
87 | })
88 | })
89 | request(app.callback())
90 | .get('/')
91 | .expect(200)
92 | .expect('content-type', 'text/html; charset=utf-8')
93 | .expect(/Zed Gu/, done)
94 | })
95 | it('should render page ok with `viewExt` option supporting `include` directive', function (done) {
96 | const app = new Koa()
97 | render(app, {
98 | root: 'example/view',
99 | layout: 'template',
100 | viewExt: 'html',
101 | cache: false
102 | })
103 |
104 | app.use(function (ctx, next) {
105 | ctx.state = ctx.state || {}
106 | ctx.state.ip = ctx.ip
107 | return next()
108 | })
109 |
110 | app.use(async function (ctx) {
111 | const users = [{ name: 'Dead Horse' }, { name: 'Runrioter Wung' }]
112 | await ctx.render('content.noext', {
113 | users
114 | })
115 | })
116 | request(app.callback())
117 | .get('/')
118 | .expect(200)
119 | .expect('content-type', 'text/html; charset=utf-8')
120 | .expect(/Dead Horse/)
121 | .expect(/Runrioter Wung/, done)
122 | })
123 | })
124 |
125 | describe('with custom node.js fs module like', () => {
126 | it('should render page ok', function (done) {
127 | const app = require('../example/app-with-custom-fs-module')
128 | request(app)
129 | .get('/')
130 | .expect(200)
131 | .expect('content-type', 'text/html; charset=utf-8')
132 | .expect(/koa ejs<\/title>/)
133 | .expect(/Dead Horse/)
134 | .expect(/Imed Jaberi/, done)
135 | })
136 | it('should render page ok with async functions', function (done) {
137 | const app = new Koa()
138 | render(app, {
139 | root: 'example/view',
140 | fs: require('mz/fs'),
141 | viewExt: 'html',
142 | layout: false,
143 | async: true
144 | })
145 |
146 | app.use(async function (ctx) {
147 | await ctx.render('async', {
148 | async sayHello (name) {
149 | return `Hello, ${name}`
150 | }
151 | })
152 | })
153 | request(app.callback())
154 | .get('/')
155 | .expect(200)
156 | .expect('content-type', 'text/html; charset=utf-8')
157 | .expect(/Hello, Jack/, done)
158 | })
159 | it('should render page ok with custom open/close', function (done) {
160 | const app = new Koa()
161 | render(app, {
162 | root: 'example/view',
163 | fs: require('mz/fs'),
164 | layout: 'template.oc',
165 | viewExt: 'html',
166 | delimiter: '?'
167 | })
168 |
169 | app.use(async function (ctx) {
170 | await ctx.render('user.oc', {
171 | user: { name: 'Zed Gu' }
172 | })
173 | })
174 | request(app.callback())
175 | .get('/')
176 | .expect(200)
177 | .expect('content-type', 'text/html; charset=utf-8')
178 | .expect(/Zed Gu/, done)
179 | })
180 | it('should render page ok with `viewExt` option supporting `include` directive', function (done) {
181 | const app = new Koa()
182 | render(app, {
183 | root: 'example/view',
184 | fs: require('mz/fs'),
185 | layout: 'template',
186 | viewExt: 'html',
187 | cache: false
188 | })
189 |
190 | app.use(function (ctx, next) {
191 | ctx.state = ctx.state || {}
192 | ctx.state.ip = ctx.ip
193 | return next()
194 | })
195 |
196 | app.use(async function (ctx) {
197 | const users = [{ name: 'Dead Horse' }, { name: 'Runrioter Wung' }]
198 | await ctx.render('content.noext', {
199 | users
200 | })
201 | })
202 | request(app.callback())
203 | .get('/')
204 | .expect(200)
205 | .expect('content-type', 'text/html; charset=utf-8')
206 | .expect(/Dead Horse/)
207 | .expect(/Runrioter Wung/, done)
208 | })
209 | })
210 | })
211 | })
212 |
--------------------------------------------------------------------------------