-
Notifications
You must be signed in to change notification settings - Fork 14
PRO-2913: add writing tests for modules documentation #237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
3ee8009
ff764f4
43a841b
f0c2af5
9d73c0d
a4a8f4e
02b6d69
d6fd36e
4820792
195c2e2
3cae079
9c6df58
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,271 @@ | ||
# Writing tests for modules | ||
|
||
BoDonkey marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Tests are useful to guarantee that the requirements of your application are met over time. | ||
They also ensure that code changes don't generate breaking artifacts. | ||
|
||
Automating tests for expected scenarios saves significant time over having to manually execute a regression test plan | ||
each time there are code changes. | ||
|
||
There are many kinds of tests: | ||
|
||
- [unit testing](https://en.wikipedia.org/wiki/Unit_testing) where we test a single part of the application, a single | ||
module or file commonly referred as a unit | ||
- [integration testing](https://en.wikipedia.org/wiki/Integration_testing) where we test multiple parts of an | ||
application working together as a group | ||
- [system testing](https://en.wikipedia.org/wiki/System_testing), sometimes referred as [end-to-end testing](https://www.indeed.com/career-advice/career-development/end-to-end-testing) where we test the entire application | ||
- and many more | ||
|
||
This documentation focuses on how to test and lint Apostrophe modules, not Apostrophe itself using integration testing. | ||
|
||
Modules should be stand-alone npm packages. They need to be hosted somewhere that our testing can access. For this | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think our docs cover turning Apostrophe modules into npm packages in general yet. And I think a lot of people reading this page will want to know about how to write integration tests for their project-level modules. Maybe we're not ready to address that yet but I think it's probably the more common use case for our audience. I'm not saying we can't get this article out there, but we should follow up with a page about how to publish your open source apostrophe module, and an update to this page to cover integration tests for project level modules. |
||
example, we are hosting this module in a GitHub repo. We will use a fictitious module named `article` to illustrate how to | ||
write tests for modules. | ||
|
||
## Requirements | ||
|
||
- A running MongoDB server | ||
|
||
## Setup | ||
|
||
This setup assumes you will use the following packages | ||
|
||
- [apostrophe](https://www.npmjs.com/package/apostrophe): *ApostropheCMS is a full-featured, open source CMS built with Node.js that seeks to empower organizations by combining in-context editing and headless architecture in a full-stack JS environment* | ||
BoDonkey marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- [eslint](https://www.npmjs.com/package/eslint): *ESLint is a tool for identifying and reporting on patterns found in ECMAScript/JavaScript code, with the goal of making code more consistent and avoiding bugs.* | ||
- [eslint-config-apostrophe](https://www.npmjs.com/package/eslint-config-apostrophe): *An ESLint configuration for ApostropheCMS core and officials modules*. You can use your own [eslint configuration](https://eslint.org/docs/latest/user-guide/configuring/) instead. | ||
- [mocha](https://www.npmjs.com/package/mocha): *Simple, flexible, fun JavaScript test framework for Node.js & The Browser* | ||
```sh | ||
npm install --save-dev apostrophe eslint eslint-config-apostrophe mocha | ||
BoDonkey marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Linting and integration testing aren't the same thing. Should we acknowledge this somewhere, maybe mention we're including linting too and what that gets us? |
||
``` | ||
|
||
You will need to add some new scripts to your `package.json`. | ||
|
||
<AposCodeBlock> | ||
```json | ||
{ | ||
"name": "article", | ||
"version": "1.0.0", | ||
"description": "A fictitious Apostrophe module", | ||
"main": "index.js", | ||
"scripts": { | ||
"lint": "npm run eslint", | ||
"eslint": "eslint .", | ||
"test": "npm run lint && mocha" | ||
}, | ||
"keywords": [], | ||
"author": "", | ||
"license": "ISC" | ||
} | ||
``` | ||
<template v-slot:caption> | ||
package.json | ||
</template> | ||
</AposCodeBlock> | ||
|
||
Add the following to `.eslintrc.json` to tell eslint to use ApostropheCMS ESLint confiuration. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good chance to say why and what this gets us. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think an additional sentence here or below the code block at around line 77 should be added. Something like: Note: I'm not sure if this is the most accurate statement. You might want to edit it. |
||
|
||
<AposCodeBlock> | ||
```json | ||
{ | ||
"extends": [ "apostrophe" ] | ||
} | ||
``` | ||
<template v-slot:caption> | ||
.eslintrc.json | ||
</template> | ||
</AposCodeBlock> | ||
|
||
When you call `npm test`, it will lint your files according to [eslint-config-apostrophe](https://www.npmjs.com/package/eslint-config-apostrophe) rules and run the tests using [mocha](https://www.npmjs.com/package/mocha). | ||
|
||
### Test folder | ||
|
||
You will need a `test/package.json` file referencing the repository URL of your module. Please replace `article` & `%article-repository-url%` with your module informations. | ||
|
||
e.g. for the module [@apostrophecms/login-hcaptcha](https://github.com/apostrophecms/login-hcaptcha) we use | ||
|
||
> `"@apostrophecms/login-hcaptcha": "git://github.com/apostrophecms/login-hcaptcha.git"` | ||
> | ||
|
||
<AposCodeBlock> | ||
```json | ||
{ | ||
"/**": "This package.json file is not actually installed.", | ||
" * ": "Apostrophe requires that all npm modules to be loaded", | ||
" */": "exist in package.json at project level, which for a test is here", | ||
"dependencies": { | ||
"apostrophe": "^3.26.0", | ||
"article": "%article-repository-url%" | ||
} | ||
} | ||
``` | ||
<template v-slot:caption> | ||
test/package.json | ||
</template> | ||
</AposCodeBlock> | ||
|
||
You don’t want to commit test files artifacts to git, please add the following to your `.gitignore` file | ||
|
||
<AposCodeBlock> | ||
```gitignore | ||
# Test files | ||
/test/apos-build | ||
/test/public | ||
/test/locales | ||
``` | ||
<template v-slot:caption> | ||
.gitignore | ||
</template> | ||
</AposCodeBlock> | ||
|
||
## Writing tests | ||
|
||
We will start with a single test file `test/index.js`. | ||
|
||
As your test grows, you can break them down into multiple files based on your liking. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "As your test grows, you can break it down into multiple files based on your liking." |
||
|
||
Mocha does not play well with arrow-functions, more info at [https://mochajs.org/#arrow-functions](https://mochajs.org/#arrow-functions) | ||
|
||
<AposCodeBlock> | ||
```javascript | ||
// We use assert strict assertion mode, value and type must be the same when doing a comparison, .i.e. === | ||
// https://nodejs.org/api/assert.html#strict-assertion-mode | ||
const assert = require('assert').strict; | ||
BoDonkey marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const t = require('apostrophe/test-lib/util.js'); | ||
|
||
// getAppConfig is used to set options for Apostrophe and the module you want to test | ||
const getAppConfig = function (options = {}) { | ||
return { | ||
article: { | ||
options: { | ||
// Pass the required options here | ||
// In the example below, we will test for the presence of a `custom` option | ||
// If your module doesn't have any options, please skip the `options` attribute | ||
...options, | ||
custom: true | ||
BoDonkey marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
}; | ||
}; | ||
|
||
// describe and it functions are provided by mocha | ||
// Usually used to "structure" the test file | ||
// They don't have a strict meaning from mocha's point of view | ||
|
||
// describe is a test suite and is used to group tests | ||
// You can have as many describe as you want in a test file | ||
// describe can be nested | ||
describe('article', function () { | ||
BoDonkey marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let apos; | ||
|
||
this.timeout(t.timeout); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a comment about whether this is optional and that you need to set an environment variable? I know you have a description of setting it below, but a reminder here would be good. |
||
|
||
// before is a hook and will run once before every describe/it found below | ||
before(async function () { | ||
apos = await t.create({ | ||
shortName: 'article', | ||
testModule: true, | ||
modules: getAppConfig() | ||
}); | ||
}); | ||
|
||
// after is a hook and will run once after every describe/it found below | ||
after(async function () { | ||
await t.destroy(apos); | ||
}); | ||
|
||
// it is used for an individual test case, e.g. testing a single function | ||
it('should have module options', function () { | ||
BoDonkey marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const actual = apos.modules.article.options; | ||
const expected = { | ||
apos, | ||
custom: true | ||
}; | ||
|
||
assert.deepEqual(actual, expected); | ||
}); | ||
}); | ||
``` | ||
<template v-slot:caption> | ||
test/index.js | ||
</template> | ||
</AposCodeBlock> | ||
|
||
### Dependencies | ||
|
||
[apostrophe/test-lib/util.js](https://github.com/apostrophecms/apostrophe/blob/main/test-lib/util.js) contains some logic to create and destroy apostrophe instances for testing purposes. | ||
|
||
It exposes: | ||
|
||
- `t.create` to create an apostrophe instance | ||
- `t.destroy` to delete the database when the apostrophe instance is destroyed | ||
- `t.createAdmin` to create an admin user | ||
- `t.getUserJar` to get a cookie jar for the admin user | ||
- `t.timeout` can be set using an environment variable `TEST_TIMEOUT`, e.g.`TEST_TIMEOUT=5000 npm test` | ||
|
||
[testModule](https://github.com/apostrophecms/apostrophe/blob/main/index.js#L468) will tweak the Apostrophe environment suitably for unit tests (i.e. set default modules options, check test files location, build module paths) | ||
|
||
- `describe` & `it` functions are provided by mocha, more info at [BDD](https://mochajs.org/#bdd) | ||
BoDonkey marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
### Output | ||
|
||
By running the test using the example `@apostrophecms/login-hcaptcha` module details and the `npm test` command, you should see the output below | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is confusing. First, you've set up to run the tests using the hypothetical article module. I realize that you include the example URL for '@apostrophecms/login-hcaptcha`, but sticking with the one example the whole way through is less confusing. Second, that module has a lot of tests. I'm worried that if the end reader attempts to run the tests for themselves with the actual module, the output will be significantly different and confusing. I would actually mockup the expected results from running this on the example module. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm OK with you guys taking this the rest of the way. |
||
|
||
``` | ||
$ npm test | ||
|
||
> @apostrophecms/[email protected] test | ||
> npm run lint && mocha | ||
|
||
|
||
> @apostrophecms/[email protected] lint | ||
> npm run eslint | ||
|
||
|
||
> @apostrophecms/[email protected] eslint | ||
> eslint . | ||
|
||
|
||
|
||
Apostrophe Login hCAPTCHA | ||
Listening at http://127.0.0.1:7780 | ||
✓ should have module options | ||
|
||
|
||
1 passing (909ms) | ||
``` | ||
|
||
### What's next? | ||
|
||
You can now test the additional methods you've provided with your module on [self](https://v3.docs.apostrophecms.org/reference/module-api/module-overview.html#methods-self). | ||
|
||
You can use any existing apostrophe modules with a `test` folder as a reference. | ||
|
||
You'll find below a non exhaustive list of such modules: | ||
|
||
- [@apostrophecms/form](https://github.com/apostrophecms/form/blob/main/test/test.js) | ||
- [@apostrophecms/login-hcaptcha](https://github.com/apostrophecms/login-hcaptcha/blob/main/test/test.js) | ||
- [@apostrophecms/svg-sprite](https://github.com/apostrophecms/svg-sprite/blob/main/test/test.js) | ||
- [@apostrophecms/scheduled-publishing](https://github.com/apostrophecms/scheduled-publishing/blob/main/test/test.js) | ||
- [@apostrophecms/sitemap](https://github.com/apostrophecms/sitemap/blob/main/test/test.js) | ||
|
||
## FAQ | ||
|
||
### MongoServerSelectionError: connect ECONNREFUSED 127.0.0.1:27017 | ||
|
||
Apostrophe assumes by default that there is MongDB server running on `127.0.0.1:27017`. | ||
|
||
You can change it by using the environment variable `APOS_MONGODB_URI`. | ||
|
||
```sh | ||
APOS_MONGODB_URI=mongodb://%mongodb-address% npm test | ||
``` | ||
|
||
### Mocha doesn't seems to work with apostrophe | ||
|
||
Starting from Apostrophe 3.26.0, we now support Mocha 9+ | ||
([Apostrophe 3.26.0 Changelog](https://github.com/apostrophecms/apostrophe/blob/main/CHANGELOG.md#3260-2022-08-03)) | ||
|
||
If you are using an older version of Apostrophe, please use Mocha 8. | ||
|
||
```sh | ||
npm install --save-dev mocha@8 | ||
``` |
Uh oh!
There was an error while loading. Please reload this page.