Skip to content

Commit 6f8eeea

Browse files
committed
Sketch of doco page
1 parent 32e035d commit 6f8eeea

File tree

1 file changed

+152
-0
lines changed

1 file changed

+152
-0
lines changed
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
---
2+
title: Testing
3+
weight: 20
4+
---
5+
6+
{{< toc >}}
7+
8+
Local testing for Eask is done using the [Jest]() testing framework.
9+
10+
A custom `TestContext` class is used to manage the execution environment for each test suite.
11+
12+
### Running Tests
13+
14+
If you have not done so already, run `npm install --dev`
15+
16+
Always run from the project root (i.e. same directory as `package.json`)
17+
18+
- run all tests `npm run test`
19+
- run a single test `npm run test path/to/test.js`
20+
- run tests with full output `npm run test-debug`
21+
- remove files created during test `npm run test-reset`
22+
23+
### Environment Vars
24+
25+
| Name | Type | Default | Meaning |
26+
|:---------------|:-------|---------|:-------------------------------------------------------------------------------------------|
27+
| `ALLOW_UNSAFE` | bool | 0 | Run tests in `testUnsafe` blocks. These can affect your emacs config or settings. |
28+
| `DEBUG` | bool | 0 | Print full output from commands in test. |
29+
| `EASK_COMMAND` | path | "eask" | Path to Eask. Usually either `eask` or `./bin/eask` (include local changes). |
30+
| `TIMEOUT` | number | 25000 | Command timeout in ms. Note this is different than Jest's timeout, which should be larger. |
31+
32+
### How to Write a Test
33+
34+
**Folder structure**
35+
36+
Tests should be in `test/js`
37+
Related tests should be in the same file with the suffix `.test.js`.
38+
39+
If the test needs some specific project files, put them in a new folder within `test/js`
40+
For example, files in `test/js/foo` would be expected to be for `foo.test.js`.
41+
42+
The exception is `test/js/empty`, which is simply an empty folder.
43+
If you use it, make sure to run `eask clean all` before your tests.
44+
45+
**Test File structure**
46+
47+
``` javascript
48+
const { TestContext } = require("./helpers");
49+
50+
describe("emacs", () => {
51+
const ctx = new TestContext("./test-js/empty");
52+
53+
beforeAll(async () => await ctx.runEask("clean all"));
54+
afterAll(() => ctx.cleanUp);
55+
56+
test("eask emacs --version", async () => {
57+
await ctx.runEask("emacs --version");
58+
});
59+
60+
test("eask emacs --batch --eval", async () => {
61+
await ctx.runEask(
62+
'emacs --batch --eval "(require (quote ert))" --eval "(ert-deftest mytest () (should-not (display-graphic-p)))" -f ert-run-tests-batch',
63+
);
64+
});
65+
});
66+
```
67+
68+
In Jest, group related tests using `describe`. Tests in the same describe block can share setup/teardown code, can be disabled as a group and are grouped under the same heading in output.
69+
70+
Describe blocks can be nested, it's a good idea to add a nested `describe` when tests run in different directories.
71+
72+
For each test directory you should create a new `TestContext` object. All `runEask` commands will use the `TestContext`'s working directory.
73+
74+
You can also use `TestContext.cleanUp()` to abort any still-running commands that were called in that context.
75+
76+
Jest's tests are in `test` blocks. Note that `it` is an alias for `test`.
77+
78+
The `expect` API matches values in different ways and usually prints a diff as part of the failure report.
79+
See Jest's [expect()](https://jestjs.io/docs/expect) API for more info.
80+
81+
Errors thrown in a `test` block will fail it and report the error.
82+
That's why many tests don't have an `expect` call, they simply check that the command succeeds.
83+
84+
### Patterns
85+
86+
Here are some common patterns for testing commands.
87+
Each of these assumes that `ctx` is a `TestContext` object.
88+
89+
Check a command succeeds:
90+
``` javascript
91+
test("eask analyze", async () => {
92+
await ctx.runEask("analyze");
93+
});
94+
```
95+
96+
Check a command fails:
97+
``` javascript
98+
test("eask analyze", async () => {
99+
await expect(ctx.runEask("analyze")).rejects.toThrow();
100+
});
101+
```
102+
103+
Check a command fails with a specific code:
104+
``` javascript
105+
// TODO
106+
```
107+
108+
Check a command produces some output:
109+
``` javascript
110+
test("eask analyze", async () => {
111+
const { stdout, stderr } = await ctx.runEask("analyze");
112+
expect(stderr).toMatch("success"); // should apppear as a substring
113+
// If you want to check both `stderr` and `stdout`, just concatenate them
114+
expect(stdout + "/n" + stderr).toMatch("success");
115+
});
116+
```
117+
118+
Match command output against a snapshot:
119+
``` javascript
120+
test("eask analyze", async () => {
121+
const res = await ctx.runEask("analyze");
122+
expect(res).toMatchSnapshot();
123+
});
124+
```
125+
126+
The first time you run this Jest will create a new snapshot. You should check this in to version control.
127+
If the snapshot changes, you can update the snapshot by running Jest with option `-u`, for example,
128+
`npm run test -u` will update all changed snapshots.
129+
130+
You can also match or ignore parts of an object to avoid time-varying or local data like usernames.
131+
132+
Commands which modify global environment, for example with `-c` or `-g` options:
133+
``` javascript
134+
const { testUnsafe } = require('./helpers');
135+
136+
// this will only run if ALLOW_UNSAFE is != 0
137+
testUnsafe("global install", async () => {
138+
// this installs in ~/.eask and changes ~/Eask
139+
await ctx.runEask("install -g foo");
140+
});
141+
```
142+
143+
### Common Problems
144+
145+
- Commands in `runEask` shouldn't include `eask`!
146+
This is an error: `ctx.runEask("eask emacs")`
147+
- When using `expect(...).rejects` it should be awaited
148+
- The folder argument to `TestContext` should be relative to project root, if it doesn't exist you may get an error `NO_ENT`
149+
- If you get an error from Jest reporting open handles, then try using `afterAll(() => ctx.cleanUp())`
150+
- There are two timeout values: one used for Jest (set in `package.json`), and one used for `node.exec`, set via env var in `./helpers.js`.
151+
The `node.exec` timeout is set lower than the Jest one, so changing timeout values for tests or by `jest.setTimeout` usually won't
152+
have an effect. Instead set the timeout on the command itself `runEask("eask emacs", { timeout: 100000 })`

0 commit comments

Comments
 (0)