Skip to content

Commit 722ad5e

Browse files
committed
[docs] Trim the testing guide and correct three factual claims
1 parent 59d2f56 commit 722ad5e

3 files changed

Lines changed: 44 additions & 107 deletions

File tree

‎docs/contributing/compatibility.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ of the rename.
2626
`src/unpoly-migrate/` mirrors the [main modules](code-organization.md#responsibilities),
2727
so a renamed `up.form` API gets its polyfill in `src/unpoly-migrate/form.js`.
2828

29-
`up.migrate` has helpers for the usual cases — renamed functions, attributes, events,
30-
properties and modules, removed options, functions that used to be async. Read
31-
`src/unpoly-migrate/migrate.js` before hand-rolling one. Two examples follow.
29+
`up.migrate` has helpers for the usual cases — renamed or removed attributes, events and
30+
properties, renamed packages, functions that used to be async. A renamed *function* is
31+
delegated by hand with `up.migrate.deprecated()`. Read `src/unpoly-migrate/migrate.js`
32+
before hand-rolling one. Two examples follow.
3233

3334

3435
### Renaming a function

‎docs/contributing/documentation.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ argument in the rendered signature:
248248
@param {string} [options.method='post']
249249
```
250250

251-
Recognized prefixes include `options`, `attrs`, `params`, `config`, `event` and
251+
Recognized prefixes include `options`, `attrs`, `params`, `config`, `eventProps` and
252252
`props`.
253253

254254
### Modifying attributes

‎docs/contributing/testing.md‎

Lines changed: 39 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ the background if none is running.
2222
`bin/test --spec="up.form"`. The full suite runs in a real browser and takes
2323
several minutes, so run it unfiltered only as a final gate — and note that
2424
[CI](commit-conventions.md#continuous-integration) runs the full matrix once you open
25-
a pull request.
25+
a pull request. Some modules are used by most others, so a change to `up.fragment`,
26+
`up.network`, `up.script`, `up.layer`, `up.util` or `up.element` can break specs anywhere
27+
and deserves the full suite.
2628

2729
A run with one failing spec looks like this:
2830

@@ -50,7 +52,7 @@ Stack traces are mapped back to the original source, and the `Debug in browser:`
5052
opens that single spec in a browser you can put DevTools on.
5153

5254
**Debug by instrumenting, not stepping.** Anything you `console.log` in a spec or in
53-
`src/unpoly` appears in the browser log that `--verbose` prints, so adding a log line
55+
`src/unpoly` appears in the browser log that `--verbose` prints (below), so adding a log line
5456
and re-running is usually the quickest way to inspect state — and the only way if you
5557
can't open a browser. When you genuinely need DevTools, open the `Debug in browser:`
5658
URL from a failing run rather than trying to step-debug the headless browser.
@@ -60,32 +62,16 @@ failure with the flag keeps everything above and adds the browser log plus an ou
6062
the DOM as it stood when the spec failed:
6163

6264
```
63-
F1) state demo → shows the HTML state on failure
64-
65-
Failure/error:
66-
Expected 'foo@example.com' to equal 'bar@example.com'.
67-
68-
Stacktrace:
69-
<jasmine internals>
70-
spec/unpoly/tmp_state_demo_spec.js:15 in anonymous function
71-
<jasmine internals>
72-
7365
Browser log:
7466
log: field value is "foo@example.com"
7567
7668
HTML state:
7769
body
78-
default-fallback
7970
#fixtures
8071
form#signup.signup-form[method="post"][action="/action"][up-submit]
8172
input[type="text"][name="email"][value="foo@example.com"]
8273
button[type="submit"]
8374
Sign up
84-
#outside-fixtures
85-
attached outside #fixtures
86-
87-
Debug in browser:
88-
http://localhost:4000/specs?spec=state%20demo%20shows%20the%20HTML%20state%20on%20failure
8975
```
9076

9177
The HTML state is a tree of CSS selectors rather than raw markup, which keeps a large
@@ -95,17 +81,9 @@ enough to identify the problem without opening a browser — a fixture that was
9581
compiled, an overlay still on the stack, a fragment inserted in the wrong place, or an
9682
attribute you expected Unpoly to have set.
9783

98-
It is rooted at `body`, so it includes elements attached outside `#fixtures` and any
99-
state Unpoly wrote onto `body` itself. Jasmine's own reporter is excluded, and
100-
`default-fallback` is a container the spec harness adds to every layer so that specs
101-
always have a main target. Very large trees are clipped at 600 nodes, with a line saying
102-
so — if you hit that, narrow the fixture rather than trusting what's shown.
103-
104-
`--verbose` also changes the stack. The compact form shows just two lines — the topmost
105-
frame in a spec file (which spec failed) and the topmost frame in `src/` (where in Unpoly
106-
it originated) — while the verbose form keeps every frame. The `<jasmine internals>`
107-
markers are Jasmine's own work: it collapses its internal frames before the runner ever
108-
sees the stack.
84+
It is rooted at `body`, so it includes elements attached outside `#fixtures`, and a very
85+
large tree is clipped with a line saying so. `--verbose` also keeps every stack frame,
86+
where the default shows only the topmost frame in a spec file and in `src/`.
10987

11088
**Options:**
11189

@@ -116,7 +94,7 @@ sees the stack.
11694
| `--browser=firefox` | Run in Firefox instead of Chrome |
11795
| `--headless=false` | Show the browser window while running |
11896
| `--stop-on-failure=false` | Keep running a spec after its first failed expectation (default: stop) |
119-
| `--csp=…` · `--es6` · `--migrate` | Serve the specs under a CSP / ES6 / unpoly-migrate variant |
97+
| `--csp=none\|nonce-only\|strict-dynamic` · `--es6` · `--migrate` | Serve the specs under a CSP / ES6 / unpoly-migrate variant |
12098

12199
`--minify` runs the specs against the bundle we actually ship. That matters because the
122100
minifier renames every `_`-prefixed member, so a spec that reaches one by name passes
@@ -129,34 +107,14 @@ A failed spec exits with a non-zero exit code, so `bin/test` composes with other
129107
tooling. The spec runner itself — its exit codes, architecture and self-tests — is
130108
documented in [`runner/README.md`](../../runner/README.md).
131109

132-
### Which specs to run
133-
134-
The full suite takes several minutes, so don't run it on every edit. While you work, run
135-
the module you are changing:
136-
137-
```
138-
bin/test --spec="up.form"
139-
```
140-
141-
Some modules are used by most others, and a change there can break specs anywhere:
142-
`up.fragment`, `up.network`, `up.script`, `up.layer`, `up.util` and `up.element`. Treat a
143-
change to those as needing the full suite.
144-
145-
Run the full suite once before you hand the change over. CI runs it on every pull request
146-
across several CSP and build variants, so it is a check, not your only safety net.
147-
148110
### If you are an agent
149111

150112
**Give the command a generous timeout.** The full suite takes minutes, and nothing caps
151113
its total runtime. A tool timeout shorter than that kills the run part-way and tells you
152114
nothing about your change.
153115

154-
You don't need to guard against a hang yourself. The runner watches for *silence*, not
155-
duration: if it sees no spec event for 30 seconds — a frozen browser session, say — it
156-
reports `no progress from the spec runner for 30s` and exits with code `2`. A single spec
157-
that never settles is caught earlier still, by Jasmine's 5-second per-spec timeout. So
158-
set your timeout from how long the suite actually takes, not from either of those
159-
numbers.
116+
You don't need to guard against a hang yourself: a run that stops making progress detects
117+
itself and exits non-zero. Set your timeout from how long the suite actually takes.
160118

161119
**Don't pipe the output through `tail` or `head`.** The part you need from a red run is
162120
the failure block, and truncating it means running the whole suite again to see what
@@ -245,7 +203,11 @@ alongside it — `form_switch_spec.js` for `[up-switch]`, `layer_open_spec.js` f
245203

246204
```
247205
$ ls spec/unpoly | grep ^form_
248-
form_spec.js form_submit_attr_spec.js form_submit_fn_spec.js form_switch_spec.js …
206+
form_spec.js
207+
form_submit_attr_spec.js
208+
form_submit_fn_spec.js
209+
form_switch_spec.js
210+
…
249211
```
250212

251213
Opening the module file also tells you what it gave away, and where that used to sit:
@@ -262,7 +224,8 @@ spec code that happens to call the feature:
262224
$ bin/find-spec "kept element"
263225
fragment_keep_spec.js:47 up.fragment / unobtrusive behavior / [up-keep] / does not run destructors within kept elements
264226
fragment_keep_spec.js:143 up.fragment / unobtrusive behavior / [up-keep] / omits a kept element from the returned up.RenderResult
265-
radio_poll_spec.js:769 up.radio / unobtrusive behavior / [up-poll] / keeps polling if an [up-keep] ancestor is kept
227+
fragment_keep_spec.js:189 up.fragment / unobtrusive behavior / [up-keep] / keeps the scroll position of an [up-viewport] within a kept element
228+
…
266229
```
267230

268231
Each path is the spec's full name, so you can hand any part of it back to `--spec`. Passing
@@ -310,23 +273,11 @@ extendDescribe('up.fragment', function() {
310273
```
311274
312275
So the split is invisible from the outside: one suite per module, unchanged full names,
313-
and `beforeEach` hooks from the module file still apply. An extracted file can extract
314-
further, as `up.render()` does — it is the only feature large enough to need it.
276+
and `beforeEach` hooks from the module file still apply.
315277
316-
Two things to know if you ever add such a file:
317-
318-
- It must **not** be listed in `spec/specs.js`, which requires every other spec file by
319-
hand. It is only ever loaded by its one `require()`. `bin/self-test` enforces both
320-
halves: it fails on a spec file that nothing loads, and on an extracted file that
321-
`specs.js` would load a second time.
322-
- It is its own module, so aliases like `const u = up.util` at the top of the module file
323-
are not in scope. Redeclare the ones you use — `bin/lint` names them.
324-
325-
The feature part of the name is the feature's own name without `up.` or `up-`:
326-
`form_switch_spec.js` for `[up-switch]`, `layer_open_spec.js` for `up.layer.open()`. When
327-
a module has both a function and a selector of that name, both files say which:
328-
`form_validate_fn_spec.js` and `form_validate_attr_spec.js`. A file may also hold several
329-
related features under a topic name, as `util_lists_spec.js` does.
278+
If you ever add such a file, the tooling keeps you honest: `bin/self-test` fails if it is
279+
listed in `spec/specs.js` (or if nothing loads it), and `bin/lint` names any alias you need
280+
to redeclare, since an extracted file is its own module.
330281
331282
332283
## Anatomy of a spec
@@ -391,34 +342,14 @@ When a spec needs the same markup more than once with variations — typically a
391342
page and the server's "new" response — build it with a function:
392343
393344
```js
394-
it('runs compilers after hungry fragments have been swapped', async function() {
395-
let compileSpy = jasmine.createSpy('compile spy')
396-
397-
let html = (prefix) => `
398-
<div id="fragment1">
399-
${prefix} fragment1
400-
</div>
401-
<div id="fragment2" up-hungry>
402-
${prefix} fragment2
403-
</div>
404-
`
405-
406-
up.compiler('#fragment1', (element) => {
407-
compileSpy(
408-
document.querySelector('#fragment1').textContent.trim(),
409-
document.querySelector('#fragment2').textContent.trim(),
410-
)
411-
})
345+
let html = (prefix) => `
346+
<div id="fragment1">${prefix} fragment1</div>
347+
<div id="fragment2" up-hungry>${prefix} fragment2</div>
348+
`
412349

413-
htmlFixtureList(html('old'))
350+
htmlFixtureList(html('old'))
414351

415-
await up.render({ target: '#fragment1', document: html('new') })
416-
417-
expect(compileSpy).toHaveBeenCalledWith(
418-
'new fragment1',
419-
'new fragment2',
420-
)
421-
})
352+
await up.render({ target: '#fragment1', document: html('new') })
422353
```
423354
424355
This keeps the two versions visibly identical apart from the one thing that differs.
@@ -434,10 +365,15 @@ const [form, field] = htmlFixtureList(`...`)
434365
up.hello(form)
435366
```
436367
437-
Keeping this explicit is deliberate. It's often not needed — behavior wired to a
438-
delegated event listener works on an uncompiled fixture — and when it *is* needed, some
439-
specs care about exactly when compilers run. An implicit `up.hello()` would take that
440-
observation away.
368+
Keeping this explicit is deliberate: some specs care about exactly when compilers run.
369+
370+
### State resets between specs
371+
372+
You never have to undo what a spec did. Fixtures are removed, and Unpoly itself is reset
373+
after every spec — compilers you registered, `up.*.config` you changed, open overlays, the
374+
cache. So a spec can call `up.compiler()` or set config freely, and the next one starts
375+
clean.
376+
441377
442378
### Overlays and styles
443379
@@ -549,7 +485,7 @@ making a mocked request time out. `jasmine.lastRequest().responseTimeout()` come
549485
jasmine-ajax and only works with the clock installed. The handful of specs that do this
550486
say so in a comment.
551487
552-
Older specs use `up.util.timer(ms, callback)`. Use `jasmine.waitTime(ms)` instead.
488+
Older specs use `up.util.timer(ms, callback)`. Use `await wait(ms)` instead.
553489
554490
### Asserting on promises
555491
@@ -579,7 +515,7 @@ it.
579515
## Matchers
580516
581517
Custom matchers live one per file in `spec/helpers/`, named after the matcher
582-
(`to_have_text.js` → `toHaveText()`). There are around ninety. Check for an existing one
518+
(`to_have_text.js` → `toHaveText()`). There are around seventy. Check for an existing one
583519
before asserting by hand — most things you'd want to say about an element, a request or
584520
a cache entry already have a matcher, and using it gives a far better failure message
585521
than a hand-rolled boolean.
@@ -608,7 +544,7 @@ The ones you'll use constantly:
608544
| `toHaveSelector(selector)` | A descendant matches the selector |
609545
| `toMatchSelector(selector)` | The element itself matches |
610546
| `toBeAttached()` · `toBeDetached()` | Whether the element is in the DOM tree |
611-
| `toBeMissing()` | A *value* is `null`, `undefined` or blank — not a DOM check |
547+
| `toBeMissing()` | A *value* is `null` or `undefined` — not a DOM check |
612548
| `toBeVisible()` · `toBeHidden()` | Rendered visibility |
613549
| `toBeFocused()` | The element has focus |
614550
| `toHaveAttribute(name, value)` | An attribute and (optionally) its value |

0 commit comments

Comments
 (0)