1 | # Zora
|
2 |
|
3 | [![npm](https://badgen.net/npm/v/zora)](https://www.npmjs.com/package/zora)
|
4 | [![install size](https://badgen.net/packagephobia/install/zora)](https://packagephobia.now.sh/result?p=zora)
|
5 |
|
6 | ## Usage
|
7 |
|
8 | The library is a _regular_ Javascript module and can be directly imported from a CDN:
|
9 |
|
10 | ```Javascript
|
11 | import {test} from 'https://unpkg.com/zora@latest/dist/index.js'
|
12 |
|
13 | test(`hello from zora`, ({ok}) => {
|
14 | ok(true, 'it worked');
|
15 | })
|
16 | ```
|
17 |
|
18 | (Like in the [following codepen](https://codepen.io/lorenzofox3/pen/LYWOaYV?editors=1111))
|
19 |
|
20 | Or installed via a package manager such [NPM](https://www.npmjs.com/) by running the command (assuming you have [Nodejs](https://nodejs.org/en/) installed on your machine):
|
21 |
|
22 | ``npm i -D zora``
|
23 |
|
24 | You can then build your testing program by using the exported ``test`` function
|
25 |
|
26 | ```Javascript
|
27 | import {test} from 'zora';
|
28 |
|
29 | test(`my very first test`, (assertion) => {
|
30 | const input = false;
|
31 | assertion.ok(input, 'input should be truthy');
|
32 | })
|
33 |
|
34 | ```
|
35 |
|
36 | You can run the testing program (with node's runtime for example) and it will start reporting its execution into the console
|
37 |
|
38 | <details>
|
39 | <summary>test-output.tap</summary>
|
40 |
|
41 | ```TAP
|
42 | TAP version 13
|
43 | # my very first test
|
44 | not ok 1 - input should be truthy
|
45 | ---
|
46 | actual: false
|
47 | expected: "truthy value"
|
48 | operator: "ok"
|
49 | at: " file:///path/to/sample.js:5:13"
|
50 | ...
|
51 |
|
52 | 1..1
|
53 | # tests 1
|
54 | # pass 0
|
55 | # fail 1
|
56 | # skip 0
|
57 |
|
58 | ```
|
59 |
|
60 | </details>
|
61 |
|
62 | ## Reporters
|
63 |
|
64 | This output format is called [TAP](https://testanything.org/tap-version-13-specification.html) (Test Anything Protocol). It is a standard text based format a machine can easily parse. It means there are [plenty of reporters](https://www.npmjs.com/search?q=tap%20reporter) you can pipe the standard output stream into (not only in the Javascript world). This will help you to tailor the reporting for your particular needs.
|
65 |
|
66 | for example, you can use [tap-diff](https://www.npmjs.com/package/tap-diff):
|
67 | ``node path/to/testing/program.js | tap-diff``
|
68 |
|
69 | You can even use basic bash command:
|
70 |
|
71 | ``node path/to/testing/program.js | grep '^not ok\|^\s'`` will output a basic, straight to the point test report:
|
72 |
|
73 | ```
|
74 | not ok 1 - input should be truthy
|
75 | ---
|
76 | actual: false
|
77 | expected: "truthy value"
|
78 | operator: "ok"
|
79 | at: " file:///path/to/sample.js:5:13"
|
80 | ...
|
81 | ```
|
82 |
|
83 | That is the beauty of using different processes to run the testing program and to format its output: it remains very flexible.
|
84 |
|
85 | ## Assertion API
|
86 |
|
87 | When you start a test suite with the ``test`` function. The spec functions you pass as argument will get an instance of the [Assertion object](../assert) so you can write a wide range of different expectations.
|
88 |
|
89 | For the best performances, all the spec functions run concurrently unless you specifically wait for them within an asynchronous function (if for some reason, you want to run some test one after the other, in a serial mode).
|
90 |
|
91 | <details>
|
92 | <summary>control-flow.js</summary>
|
93 |
|
94 | ```Javascript
|
95 | import {test} from 'zora';
|
96 |
|
97 | let state = 0;
|
98 |
|
99 | test('test 1', t => {
|
100 | t.ok(true);
|
101 | state++;
|
102 | });
|
103 |
|
104 | test('test 2', t => {
|
105 | //Maybe yes maybe no, you have no guarantee ! In this case it will work as everything is sync
|
106 | t.equal(state, 1);
|
107 | });
|
108 |
|
109 | //Same thing here even in nested tests
|
110 | test('grouped', t => {
|
111 | let state = 0;
|
112 |
|
113 | t.test('test 1', t => {
|
114 | t.ok(true);
|
115 | state++;
|
116 | });
|
117 |
|
118 | t.test('test 2', t => {
|
119 | //Maybe yes maybe no, you have no guarantee ! In this case it will work as everything is sync
|
120 | t.equal(state, 1);
|
121 | });
|
122 | });
|
123 |
|
124 | //And
|
125 | test('grouped', t=>{
|
126 | let state = 0;
|
127 |
|
128 | t.test('test 1', async t=>{
|
129 | t.ok(true);
|
130 | await wait(100);
|
131 | state++;
|
132 | });
|
133 |
|
134 | test('test 2', t=>{
|
135 | t.equal(state, 0, 'see the old state value as it will have started to run before test 1 is done');
|
136 | });
|
137 | });
|
138 |
|
139 | //But
|
140 | test('grouped', async t => {
|
141 | let state = 0;
|
142 |
|
143 | //specifically WAIT for the end of this test before moving on !
|
144 | await t.test('test 1', async t => {
|
145 | t.ok(true);
|
146 | await wait(100);
|
147 | state++;
|
148 | });
|
149 |
|
150 | test('test 2', t => {
|
151 | t.equal(state, 1, 'see the updated value!');
|
152 | });
|
153 | });
|
154 | ```
|
155 |
|
156 | </details>
|
157 |
|
158 |
|
159 | ## Environment variables
|
160 |
|
161 | You can _configure_ the testing program with environment variables. With nodejs, simply pass it with the command line:
|
162 |
|
163 | ``ZORA_REPORTER=json node path/to/testing/program.js``
|
164 |
|
165 | In the browser, you have to set it as a global before the testing program runs:
|
166 |
|
167 | ```HTML
|
168 | <script>
|
169 | window.ZORA_REPORTER='json'
|
170 | </script>
|
171 | <script type="module">
|
172 | import {test} from 'url/to/zora';
|
173 |
|
174 | test('some test', (t) => {
|
175 | t.ok(true);
|
176 | })
|
177 | </script>
|
178 | ```
|
179 |
|
180 | ### ZORA_REPORTER=json
|
181 |
|
182 | By default, the output is a TAP stream; but you can decide to produce a stream defined by [the zora json protocol messages](../reporters) if you which to build a custom reporter on top of it.
|
183 |
|
184 | ### ZORA_ONLY=true
|
185 |
|
186 | Beside the ``test`` function you can use the ``only`` function if you wish to skip all the other tests. However, from the testing program perspective, ``only`` is meaningless: it is just a convenience for a developer, locally on its machine.
|
187 | So if you wish to use ``only`` you need to pass the ``ZORA_ONLY`` environment variable, otherwise the program will throw an exception to prevent ``only`` statement to slip in the remote versioning control system.
|
188 |
|
189 | Beware that if you want to run only a nested test suite, all the parent test suites must use the ``only statement`:`
|
190 |
|
191 | <details>
|
192 | <summary>test-with-only.js</summary>
|
193 |
|
194 | ```Javascript
|
195 | import {only, test} from 'zora';
|
196 |
|
197 | test('will be skipped', t => {
|
198 | t.ok(false);
|
199 | })
|
200 |
|
201 | only('some test', t => {
|
202 |
|
203 | // will be skipped as well
|
204 | t.test('some nested test', t => {
|
205 | t.ok(false);
|
206 | });
|
207 |
|
208 | // will run
|
209 | t.only('some other nested test', t => {
|
210 | t.ok(true);
|
211 | });
|
212 | });
|
213 | ```
|
214 |
|
215 | </details>
|
216 |
|
217 | ### ZORA_TIMEOUT
|
218 |
|
219 | In milliseconds: change the default test timeout value (see below)
|
220 |
|
221 | ## test timeout
|
222 |
|
223 | If a test hangs or takes too long to complete, it will report a failure. By default, the threshold is 5000ms. You can change that global value thanks to the ``ZORA_TIMEOUT`` environment variable.
|
224 | You can change that value for a given text as well, thanks to the options object:
|
225 |
|
226 | <details>
|
227 | <summary>timeout example</summary>
|
228 |
|
229 | ```Javascript
|
230 | test(
|
231 | 'broken promise',
|
232 | ({ ok }) => {
|
233 | return new Promise(() => {}).then(() => {
|
234 | ok(true);
|
235 | });
|
236 | },
|
237 | { timeout: 500 }
|
238 | );
|
239 | ```
|
240 |
|
241 | </details>
|
242 |
|
243 | ## skip a test
|
244 |
|
245 | You can skip a test using the root level ``skip`` function or within a test suite using the ``skip`` method of the assertion object
|
246 |
|
247 | <details>
|
248 | <summary>test-with-skip.js</summary>
|
249 |
|
250 | ```Javascript
|
251 | import {skip, test} from 'zora';
|
252 |
|
253 | skip('will be skipped', t => {
|
254 | t.ok(false);
|
255 | })
|
256 |
|
257 | test('some test', t => {
|
258 |
|
259 | // will be skipped as well
|
260 | t.skip('some nested test', t => {
|
261 | t.ok(false);
|
262 | });
|
263 |
|
264 | // will run
|
265 | t.test('some other nested test', t => {
|
266 | t.ok(true);
|
267 | });
|
268 | });
|
269 | ```
|
270 |
|
271 | </details>
|