|
52 | 52 |
|
53 | 53 | **Tests are still a Work In Progress.** |
54 | 54 | The tests rely on `mocha`, `chai`, `sinon`, and `sinon-chai`, and are currently a mix of system and unit tests. |
| 55 | + |
| 56 | +### Naming |
| 57 | + |
| 58 | +**TODO:** Split out system tests from unit tests and then revise the below guidlines. |
| 59 | + |
| 60 | +These guidelines are inspired by [Better Specs { rspec guidelines with ruby }](https://www.betterspecs.org). Given that these guidelines are, by necessity, quite subjective, consider them as beneficial for the consistency rather than the "correctness" that they provide. |
| 61 | + |
| 62 | +The linter should catch basic stylistic errors (e.g. prefer arrow functions unless `this` is needed). |
| 63 | + |
| 64 | +--- |
| 65 | + |
| 66 | +When naming individual `it` blocks, the resulting test name should read like a sentence. For example: `it('returns false if the repo has no filters')`. |
| 67 | + |
| 68 | +Directly describe what the test should do. Use verbs like `returns`, `errors`, `responds`, `reads`, etc. rather than prefixing tests with `should`, suffixing them with `correctly`, etc.. For example: |
| 69 | + |
| 70 | +``` javascript |
| 71 | +/* Bad */ |
| 72 | +it('should read globs from `.gitattributes` correctly', function () { |
| 73 | + // ... |
| 74 | +}); |
| 75 | + |
| 76 | +/* Good */ |
| 77 | +it('reads globs from `.gitattributes`', function () { |
| 78 | + // ... |
| 79 | +}); |
| 80 | +``` |
| 81 | + |
| 82 | +--- |
| 83 | + |
| 84 | +If you have the temptation to start a test with `can`, try to restructure the test to use a nested `describe` instead (whose message starts with `when`). For example: |
| 85 | + |
| 86 | +``` javascript |
| 87 | +/* Bad */ |
| 88 | +it('can initialize a non-LFS repo', function () { |
| 89 | + // ... |
| 90 | +}); |
| 91 | + |
| 92 | +/* Good */ |
| 93 | +describe('when provided a non-LFS repo', () => { |
| 94 | + it('initializes the repo', function () { |
| 95 | + // ... |
| 96 | + }); |
| 97 | +}); |
| 98 | +``` |
| 99 | + |
| 100 | +--- |
| 101 | + |
| 102 | +For tests whose behavior varies cross-platform, surround the tests with a `process.platform` test. Be sure to add tests for all platforms where behavior could vary, even if you cannot run them locally. Because CI will run on Windows, macOS, and Linux, this should not be an obstacle to thorough test coverage. For example: |
| 103 | + |
| 104 | +``` javascript |
| 105 | +/* Bad */ |
| 106 | +describe('when on Windows', () => { |
| 107 | + beforeEach(() => { |
| 108 | + sinon.stub(process, 'platform').returns('win32'); |
| 109 | + }); |
| 110 | + |
| 111 | + it('runs the provided command', function () { |
| 112 | + // ... |
| 113 | + }); |
| 114 | +}); |
| 115 | + |
| 116 | +describe('when on macOS', () => { |
| 117 | + beforeEach(() => { |
| 118 | + sinon.stub(process, 'platform').returns('darwin'); |
| 119 | + }); |
| 120 | + |
| 121 | + it('runs the provided command', function () { |
| 122 | + // ... |
| 123 | + }); |
| 124 | +}); |
| 125 | + |
| 126 | +describe('when on Linux', () => { |
| 127 | + beforeEach(() => { |
| 128 | + sinon.stub(process, 'platform').returns('linux'); |
| 129 | + }); |
| 130 | + |
| 131 | + it('runs the provided command', function () { |
| 132 | + // ... |
| 133 | + }); |
| 134 | +}); |
| 135 | + |
| 136 | +/* Good */ |
| 137 | +switch (process.platform) { |
| 138 | + case 'win32': |
| 139 | + it('runs the provided command', function () { |
| 140 | + // ... |
| 141 | + }); |
| 142 | + break; |
| 143 | + case 'macOS': |
| 144 | + it('runs the provided command', function () { |
| 145 | + // ... |
| 146 | + }); |
| 147 | + break; |
| 148 | + case 'linux': |
| 149 | + it('runs the provided command', function () { |
| 150 | + // ... |
| 151 | + }); |
| 152 | + break; |
| 153 | +} |
| 154 | +``` |
| 155 | + |
| 156 | +--- |
| 157 | + |
| 158 | +When referring to parameters, use `provided` rather than `passed-in`, `given`, etc. For example: |
| 159 | + |
| 160 | +``` javascript |
| 161 | +/* Bad */ |
| 162 | +it('runs the passed-in command', function () { |
| 163 | + // ... |
| 164 | +}); |
| 165 | + |
| 166 | +/* Good */ |
| 167 | +it('runs the provided command', function () { |
| 168 | + // ... |
| 169 | +}); |
| 170 | +``` |
| 171 | + |
| 172 | +--- |
| 173 | + |
| 174 | +Each implementation file should correspond to a similarly-named `<file name>.spec.js` test file in the same relative location. For example, `src/callbacks/check.js` should have a test file located in `test/tests/callbacks/check.spec.js`. |
| 175 | + |
| 176 | +The top-level `describe` should be named after the file. `describe`s for each function should be named after the function itself. On a related note, each function should have its own `describe` block, even if there is only `it` block inside it. In the case that a function does not have a pre-defined name (e.g. it's an anonymous function exported as the default), refer to it as `the default export`. For example: |
| 177 | + |
| 178 | +``` javascript |
| 179 | +/* For named exports: */ |
| 180 | +describe('helpers', () => { // Named after the file name, `helpers.spec.js` |
| 181 | + describe('hasLfsFilters', () => { // Named after the exported function name, `hasLfsFilters` |
| 182 | + // ... |
| 183 | + }); |
| 184 | +}); |
| 185 | + |
| 186 | +/* For default exports: */ |
| 187 | +describe('check', () => { |
| 188 | + describe('the default export', () => { |
| 189 | + // ... |
| 190 | + }); |
| 191 | +}); |
| 192 | +``` |
0 commit comments