ultimate-jekyll-manager 1.1.10 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/CLAUDE.md +138 -1775
- package/README.md +49 -20
- package/dist/build.js +3 -0
- package/dist/cli.js +1 -0
- package/dist/commands/test.js +56 -0
- package/dist/defaults/CLAUDE.md +72 -6
- package/dist/gulp/tasks/defaults.js +15 -2
- package/dist/index.js +4 -0
- package/dist/test/assert.js +120 -0
- package/dist/test/fixtures/consumer-site/_site/about.html +13 -0
- package/dist/test/fixtures/consumer-site/_site/assets/css/main.bundle.css +2 -0
- package/dist/test/fixtures/consumer-site/_site/assets/js/main.bundle.js +6 -0
- package/dist/test/fixtures/consumer-site/_site/build.json +11 -0
- package/dist/test/fixtures/consumer-site/_site/index.html +28 -0
- package/dist/test/fixtures/consumer-site/_site/service-worker.js +29 -0
- package/dist/test/fixtures/consumer-site/package.json +6 -0
- package/dist/test/harness/page/index.html +51 -0
- package/dist/test/index.js +63 -0
- package/dist/test/runner.js +402 -0
- package/dist/test/runners/boot.js +109 -0
- package/dist/test/runners/chromium.js +255 -0
- package/dist/test/server.js +127 -0
- package/dist/test/suites/boot/service-worker.test.js +84 -0
- package/dist/test/suites/boot/site-loads.test.js +65 -0
- package/dist/test/suites/build/cli.test.js +49 -0
- package/dist/test/suites/build/collect-text-nodes.test.js +37 -0
- package/dist/test/suites/build/dictionary.test.js +17 -0
- package/dist/test/suites/build/expect.test.js +59 -0
- package/dist/test/suites/build/exports.test.js +32 -0
- package/dist/test/suites/build/logger.test.js +62 -0
- package/dist/test/suites/build/manager.test.js +186 -0
- package/dist/test/suites/build/merge-jekyll-configs.test.js +95 -0
- package/dist/test/suites/build/mode-helpers.test.js +65 -0
- package/dist/test/suites/build/template-transform.test.js +94 -0
- package/dist/test/suites/build/templating-brackets.test.js +46 -0
- package/dist/test/suites/build/validate-yaml.test.js +60 -0
- package/dist/test/suites/page/dom-baseline.test.js +34 -0
- package/dist/test/suites/page/harness-globals.test.js +38 -0
- package/dist/test/suites/page/prerendered-icons.test.js +32 -0
- package/dist/utils/mode-helpers.js +84 -0
- package/docs/_legacy-claude-md.md +1832 -0
- package/docs/cross-context-helpers.md +75 -0
- package/docs/test-boot-layer.md +110 -0
- package/docs/test-framework.md +183 -0
- package/package.json +8 -5
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Cross-context Helpers
|
|
2
|
+
|
|
3
|
+
`src/utils/mode-helpers.js` exposes four shared helpers mixed into every UJM Manager via `attachTo(Manager)`. Mirrors the same pattern in EM and BXM. Used when behavior should differ by *what kind of process* you're in — short-circuit network probes in tests, suppress dev-only banners in production, etc.
|
|
4
|
+
|
|
5
|
+
## API
|
|
6
|
+
|
|
7
|
+
| Method | Returns | Purpose |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| `Manager.isTesting()` | `boolean` | True when UJM's test framework is running this process. Set by `npx mgr test` (`UJ_TEST_MODE=true`) and consumer test setups that want the same signal. |
|
|
10
|
+
| `Manager.isDevelopment()` | `boolean` | True when running in dev mode (not a production build). Reads `UJ_BUILD_MODE` / `NODE_ENV` / `UJ_IS_SERVER` / `window.Configuration.uj.environment` depending on context. |
|
|
11
|
+
| `Manager.isProduction()` | `boolean` | Inverse of `isDevelopment()`. |
|
|
12
|
+
| `Manager.getVersion()` | `string \| null` | UJM's version from `<cwd>/package.json#version`. Null if no `package.json` (e.g. shipped browser bundle). |
|
|
13
|
+
|
|
14
|
+
All four are available both **statically** on the Manager constructor and on **`Manager.prototype`**, so these all work:
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
const Manager = require('ultimate-jekyll-manager/build');
|
|
18
|
+
Manager.isTesting(); // static
|
|
19
|
+
new Manager().isTesting(); // instance
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## When to use
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
// In a build helper that fetches Firebase auth files:
|
|
26
|
+
async function fetchFirebaseAuthFiles() {
|
|
27
|
+
if (Manager.isTesting()) {
|
|
28
|
+
return; // short-circuit — tests provide their own stubs
|
|
29
|
+
}
|
|
30
|
+
// ...real fetch
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// In a gulp task that opens the dev browser:
|
|
34
|
+
function maybeOpenBrowser() {
|
|
35
|
+
if (Manager.isBuildMode() || Manager.isTesting()) return;
|
|
36
|
+
// ...exec `open` etc.
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// In a frontend module that logs verbose debug info:
|
|
40
|
+
if (manager.isDevelopment()) {
|
|
41
|
+
console.log('[dev] webManager loaded with', cfg);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Don't use these for "should I hit dev or prod backends"** — that's a config concern. Use `Manager.getEnvironment()` (returns `'development'` or `'production'` strings) for that distinction.
|
|
46
|
+
|
|
47
|
+
## How `isDevelopment` is detected
|
|
48
|
+
|
|
49
|
+
Order of checks:
|
|
50
|
+
|
|
51
|
+
1. **Build-time Node**: `process.env.UJ_BUILD_MODE === 'true'` → production. `process.env.NODE_ENV === 'development'` → development. `process.env.UJ_IS_SERVER === 'true'` → production.
|
|
52
|
+
2. **Browser**: `window.Configuration.uj.environment` if present (`'development'` or `'production'`).
|
|
53
|
+
3. Default → `false`.
|
|
54
|
+
|
|
55
|
+
## How `isTesting` is detected
|
|
56
|
+
|
|
57
|
+
Two checks (either is sufficient):
|
|
58
|
+
|
|
59
|
+
1. **Node**: `process.env.UJ_TEST_MODE === 'true'`. Set automatically by `npx mgr test`.
|
|
60
|
+
2. **Browser**: `globalThis.UJ_TEST_MODE === true`. Set automatically by UJM's `page`-layer harness HTML before any consumer code runs.
|
|
61
|
+
|
|
62
|
+
This means consumer code that calls `Manager.isTesting()` from a tab context gets the right answer — Node-only check would always return false in a browser.
|
|
63
|
+
|
|
64
|
+
## Adding new helpers
|
|
65
|
+
|
|
66
|
+
If you find yourself writing the same `if (process.env.UJ_FOO === 'true') ...` check more than twice, factor it into `mode-helpers.js`. Things to consider:
|
|
67
|
+
|
|
68
|
+
- Does the helper need to work in **all** contexts (Node build-time + browser page + service worker)? If yes, gate every check with `typeof process !== 'undefined'` / `typeof window !== 'undefined'` so the same code runs everywhere.
|
|
69
|
+
- Should it be mixed into static AND prototype? Almost always yes — the static form is for build-time CLI usage, the instance form for runtime use.
|
|
70
|
+
- Add a test in `src/test/suites/build/mode-helpers.test.js` that toggles the underlying env var and asserts both states.
|
|
71
|
+
|
|
72
|
+
## See also
|
|
73
|
+
|
|
74
|
+
- [test-framework.md](test-framework.md) — the test harness that sets `UJ_TEST_MODE`
|
|
75
|
+
- [cli.md](cli.md) — full env-var matrix
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Boot Layer
|
|
2
|
+
|
|
3
|
+
The boot layer runs Puppeteer against a real built `_site/` served by a tiny embedded HTTP server. It's the integration smoke that catches "did my actually-shipped site boot?" regressions — things plain-Node build tests can't see.
|
|
4
|
+
|
|
5
|
+
## Why a real HTTP server (not `file://`)
|
|
6
|
+
|
|
7
|
+
Service workers refuse to register from `file://` URLs. Since SW registration / activation / cache-name composition is a key boot signal, the harness spins up a zero-dep HTTP server (`src/test/server.js`, ~100 lines of pure Node `http`) on an ephemeral loopback port and points Puppeteer at it.
|
|
8
|
+
|
|
9
|
+
The server also serves files with correct MIME types (text/html / text/javascript / text/css / application/json / image/png / etc.) and sets `Service-Worker-Allowed: /` so consumers can register a SW from any subdirectory.
|
|
10
|
+
|
|
11
|
+
## `_site/` discovery order
|
|
12
|
+
|
|
13
|
+
The runner picks the first of these that has an `index.html`:
|
|
14
|
+
|
|
15
|
+
1. `UJ_TEST_BOOT_DIR` — absolute path. Full override. Useful when your build pipeline writes elsewhere (`build/`, `public/`, custom dirs).
|
|
16
|
+
2. `UJ_TEST_BOOT_PROJECT/_site` — auto-set when UJM tests itself; points at the fixture site under `src/test/fixtures/consumer-site/`. Consumers can set this manually if they want to run boot tests against a sibling project.
|
|
17
|
+
3. `<cwd>/_site` — the default for UJM consumers. After `npm run build`, Jekyll writes here.
|
|
18
|
+
|
|
19
|
+
If none match, boot tests are reported as skipped with a clear "run `npm run build` first" message.
|
|
20
|
+
|
|
21
|
+
## Fixture site vs consumer site
|
|
22
|
+
|
|
23
|
+
UJM's own framework boot suites assert against a fixture `_site/` at `src/test/fixtures/consumer-site/_site/`. The fixture is hand-built (no real Jekyll run needed during framework self-tests) and contains the minimum surface needed to verify boot:
|
|
24
|
+
|
|
25
|
+
- `index.html` — renders title + h1
|
|
26
|
+
- `about.html` — proves Jekyll-style `/about` → `/about.html` suffix fallback works
|
|
27
|
+
- `service-worker.js` — registers + activates + responds to `get-cache-name` postMessage
|
|
28
|
+
- `build.json` — proves UJM-generated metadata is served as application/json
|
|
29
|
+
- `assets/css/main.bundle.css`, `assets/js/main.bundle.js` — prove MIME routing
|
|
30
|
+
|
|
31
|
+
When a real consumer runs `npx mgr test`, framework boot suites are **excluded** (their assertions reference fixture-only content like "UJM Fixture Consumer"). Consumers write their own boot tests under `test/boot/` against their real `_site/`.
|
|
32
|
+
|
|
33
|
+
## Single-Chromium-instance amortization
|
|
34
|
+
|
|
35
|
+
All boot tests run inside one Puppeteer browser instance. Per-test cost: ~150ms for the page navigation + assertions. Browser startup (~1s) is paid once per `npx mgr test --layer boot` invocation, not once per test.
|
|
36
|
+
|
|
37
|
+
## What to assert
|
|
38
|
+
|
|
39
|
+
Good boot-test targets (high-signal, low-flake):
|
|
40
|
+
|
|
41
|
+
| Assertion | Why it matters |
|
|
42
|
+
|---|---|
|
|
43
|
+
| Home page has expected title / h1 | Catches "template variable didn't resolve" + "Liquid build failed" silently |
|
|
44
|
+
| `/some-route` resolves with 200 | Catches Jekyll permalink regressions + suffix-fallback edge cases |
|
|
45
|
+
| `build.json` is present + parses + has expected `config.brand.id` | Catches `gulp/build-config` regressions where the runtime config injection broke |
|
|
46
|
+
| `service-worker.js` MIME is `text/javascript` | A `text/html` MIME means the SW route is wrong; SW registration silently fails |
|
|
47
|
+
| SW reaches `activated` state | Catches "skipWaiting / clients.claim never wired" |
|
|
48
|
+
| SW responds to a postMessage with expected cache name | Catches "UJ_BUILD_JSON injection broken" or "cache-name composition regressed" |
|
|
49
|
+
| No `console.error` events fire during page load | Catches broken bundles, malformed `window.Configuration`, webManager init crashes |
|
|
50
|
+
|
|
51
|
+
Avoid (high-flake):
|
|
52
|
+
|
|
53
|
+
- "Wait for a specific element to be visible" without `waitForSelector` — pages render asynchronously
|
|
54
|
+
- Animation-dependent assertions (CSS transition completes, etc.) — timing-sensitive
|
|
55
|
+
- Anything that hits production Firebase / external APIs — boot tests should be hermetic
|
|
56
|
+
|
|
57
|
+
## Example consumer boot test
|
|
58
|
+
|
|
59
|
+
From Chatsy's `test/boot/site.test.js`:
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
module.exports = {
|
|
63
|
+
layer: 'boot',
|
|
64
|
+
description: 'Chatsy _site/ loads + SW registers',
|
|
65
|
+
type: 'group',
|
|
66
|
+
tests: [
|
|
67
|
+
{
|
|
68
|
+
description: 'home renders with title',
|
|
69
|
+
inspect: async ({ site, page, expect }) => {
|
|
70
|
+
const res = await page.goto(site.baseUrl + '/', { waitUntil: 'domcontentloaded' });
|
|
71
|
+
expect(res.status()).toBe(200);
|
|
72
|
+
expect((await page.title()).length).toBeGreaterThan(0);
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
description: 'service-worker.js has javascript content type',
|
|
77
|
+
inspect: async ({ site, page, expect }) => {
|
|
78
|
+
const res = await page.goto(site.baseUrl + '/service-worker.js');
|
|
79
|
+
expect(/(text|application)\/javascript/.test(res.headers()['content-type'])).toBe(true);
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Build-then-test pattern
|
|
87
|
+
|
|
88
|
+
For local development:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npm run build # gulp pipeline produces _site/
|
|
92
|
+
npx mgr test --layer boot
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
For CI: do the same. Don't try to share `_site/` between machines — Jekyll's incremental cache makes that brittle. Always build, then test.
|
|
96
|
+
|
|
97
|
+
## Debugging
|
|
98
|
+
|
|
99
|
+
Set `UJ_TEST_DEBUG=1` to see Puppeteer's console output piped to your terminal:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
UJ_TEST_DEBUG=1 npx mgr test --layer boot
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Useful when a boot test fails with an opaque error — you'll see the actual `console.error` that triggered the failure plus any other tab-side logging.
|
|
106
|
+
|
|
107
|
+
## See also
|
|
108
|
+
|
|
109
|
+
- [test-framework.md](test-framework.md) — overall harness reference
|
|
110
|
+
- [build-system.md](build-system.md) — the gulp pipeline that produces `_site/`
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Test Framework
|
|
2
|
+
|
|
3
|
+
UJM ships a built-in three-layer test harness. `npx mgr test` discovers framework suites from `<ujm>/dist/test/suites/**/*.js` and consumer suites from `<cwd>/test/**/*.js`, partitions by `layer`, and runs each layer in the right environment. Same shape as the sister harnesses in EM (electron-manager) and BXM (browser-extension-manager).
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx mgr test # all layers
|
|
9
|
+
npx mgr test --layer build # plain Node, fast
|
|
10
|
+
npx mgr test --layer page # headless Chromium tab against harness HTML
|
|
11
|
+
npx mgr test --layer boot # headless Chromium against built _site/
|
|
12
|
+
npx mgr test --filter foo # filter tests by name substring
|
|
13
|
+
npx mgr test --reporter json # machine-readable __UJM_TEST__ events
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`npm test` works too — added to consumer `package.json#scripts.test` on `npx mgr setup`.
|
|
17
|
+
|
|
18
|
+
## Layers
|
|
19
|
+
|
|
20
|
+
| Layer | Runs in | Use for |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `build` | Plain Node, ~ms | `Manager.getConfig/getPackage/getUJMConfig`, CLI alias resolution, gulp pure helpers (`mergeJekyllConfigs`, `validateYAMLFrontMatter`, `createTemplateTransform`, `collectTextNodes`), mode-helpers env gating, templating brackets |
|
|
23
|
+
| `page` | Headless Chromium tab via Puppeteer | Frontend Manager lifecycle, `window.Configuration` plumbing, DOM assertions, prerendered icons template, anything that needs real `window`/`document` |
|
|
24
|
+
| `boot` | Headless Chromium loading the consumer's built `_site/` via a tiny local HTTP server | End-to-end smoke: site builds + serves, pages render, service worker registers + activates + responds, no console errors |
|
|
25
|
+
|
|
26
|
+
There is no `main`/`background` layer (EM/BXM have those because they own long-running runtime processes; UJM does not).
|
|
27
|
+
|
|
28
|
+
## Writing a test
|
|
29
|
+
|
|
30
|
+
Every test file is a CommonJS module exporting one of three forms:
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
// Standalone
|
|
34
|
+
module.exports = {
|
|
35
|
+
layer: 'build',
|
|
36
|
+
description: 'config has brand.id',
|
|
37
|
+
timeout: 5000,
|
|
38
|
+
run: async (ctx) => {
|
|
39
|
+
const Manager = require('ultimate-jekyll-manager/build');
|
|
40
|
+
const cfg = Manager.getConfig('project');
|
|
41
|
+
ctx.expect(cfg.brand.id).toBeTruthy();
|
|
42
|
+
},
|
|
43
|
+
cleanup: async (ctx) => { /* optional */ },
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Suite — sequential, stops on first failure, shares `ctx.state`
|
|
47
|
+
module.exports = {
|
|
48
|
+
type: 'suite',
|
|
49
|
+
layer: 'build',
|
|
50
|
+
description: 'config flow',
|
|
51
|
+
tests: [
|
|
52
|
+
{ name: 'load', run: async (ctx) => { ctx.state.cfg = Manager.getConfig('project'); } },
|
|
53
|
+
{ name: 'check', run: async (ctx) => { ctx.expect(ctx.state.cfg.brand.id).toBe('foo'); } },
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Group — runs ALL tests even if some fail
|
|
58
|
+
module.exports = {
|
|
59
|
+
type: 'group',
|
|
60
|
+
layer: 'build',
|
|
61
|
+
tests: [ /* ... */ ],
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// Array form → implicit group
|
|
65
|
+
module.exports = [
|
|
66
|
+
{ name: 'a', run: async (ctx) => { /* ... */ } },
|
|
67
|
+
{ name: 'b', run: async (ctx) => { /* ... */ } },
|
|
68
|
+
];
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### The `ctx` (test context)
|
|
72
|
+
|
|
73
|
+
Every `run(ctx)` and `cleanup(ctx)` callback receives:
|
|
74
|
+
|
|
75
|
+
| Property | Description |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `ctx.expect` | Jest-compatible assertion (`toBe`, `toEqual`, `toBeTruthy`, `toContain`, `toMatch`, `toThrow`, `toBeGreaterThan`, etc. + `.not.` negation) |
|
|
78
|
+
| `ctx.state` | Plain object shared across tests in a suite/group |
|
|
79
|
+
| `ctx.layer` | Current layer name |
|
|
80
|
+
| `ctx.skip(reason)` | Throws SkipError — the runner records as skipped |
|
|
81
|
+
|
|
82
|
+
### Boot-layer test shape
|
|
83
|
+
|
|
84
|
+
Boot tests use `inspect` instead of `run`. The callback receives `{ site, page, expect, projectRoot }`:
|
|
85
|
+
|
|
86
|
+
```js
|
|
87
|
+
module.exports = {
|
|
88
|
+
layer: 'boot',
|
|
89
|
+
description: 'home renders + SW registers',
|
|
90
|
+
timeout: 15000,
|
|
91
|
+
inspect: async ({ site, page, expect, projectRoot }) => {
|
|
92
|
+
const res = await page.goto(site.baseUrl + '/');
|
|
93
|
+
expect(res.status()).toBe(200);
|
|
94
|
+
expect(await page.title()).toBeTruthy();
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
| Property | Description |
|
|
100
|
+
|---|---|
|
|
101
|
+
| `site.baseUrl` | `http://127.0.0.1:<port>` — the harness HTTP server root |
|
|
102
|
+
| `site.port` | Ephemeral port the local server bound to |
|
|
103
|
+
| `site.root` | Absolute path to the served `_site/` |
|
|
104
|
+
| `page` | Puppeteer Page (fresh per test) |
|
|
105
|
+
| `expect` | Same Jest-compatible matchers |
|
|
106
|
+
| `projectRoot` | Absolute path to the consumer project |
|
|
107
|
+
|
|
108
|
+
## Consumer pattern — use the public Manager API
|
|
109
|
+
|
|
110
|
+
When writing consumer tests, **use the public Manager API** — don't reach into UJM's transitive deps:
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
// Good — uses the public API
|
|
114
|
+
const Manager = require('ultimate-jekyll-manager/build');
|
|
115
|
+
const cfg = Manager.getUJMConfig();
|
|
116
|
+
const pkg = Manager.getPackage('project');
|
|
117
|
+
|
|
118
|
+
// Bad — reaches into UJM's transitive deps. Brittle: if UJM swaps json5 for
|
|
119
|
+
// jsonc-parser, your test breaks even though UJM's public API hasn't changed.
|
|
120
|
+
const json5 = require('json5');
|
|
121
|
+
const fs = require('fs');
|
|
122
|
+
const cfg = json5.parse(fs.readFileSync('config/ultimate-jekyll-manager.json', 'utf8'));
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The public surface exposed by `require('ultimate-jekyll-manager/build')` includes:
|
|
126
|
+
|
|
127
|
+
- `Manager.getConfig(type)` — reads `_config.yml` (type: `'project'` or `'main'`)
|
|
128
|
+
- `Manager.getPackage(type)` — reads `package.json` (type: `'project'` or `'main'`)
|
|
129
|
+
- `Manager.getUJMConfig()` — reads `config/ultimate-jekyll-manager.json` (JSON5)
|
|
130
|
+
- `Manager.getRootPath(type)` — project cwd or UJM package root
|
|
131
|
+
- `Manager.getEnvironment()` — `'development'` or `'production'`
|
|
132
|
+
- `Manager.isBuildMode()` / `isQuickMode()` / `isServer()` / `actLikeProduction()`
|
|
133
|
+
- `Manager.isTesting()` / `isDevelopment()` / `isProduction()` / `getVersion()` (from `mode-helpers.js`)
|
|
134
|
+
- `Manager.getMemoryUsage()` / `Manager.logMemory(logger, label)` / `Manager.processBatches(items, size, fn, logger)`
|
|
135
|
+
- `Manager.logger(name)` — returns a `Logger` instance
|
|
136
|
+
- `Manager.require(path)` — escape hatch when you really need a UJM transitive dep
|
|
137
|
+
|
|
138
|
+
See [docs/cross-context-helpers.md](cross-context-helpers.md) for `isTesting`/`isDevelopment` semantics.
|
|
139
|
+
|
|
140
|
+
## Reporter contract — `__UJM_TEST__` JSON-line events
|
|
141
|
+
|
|
142
|
+
`--reporter json` emits one JSON line per event for external tools (CI dashboards, IDE plugins):
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
__UJM_TEST__{"event":"result","name":"my-test","passed":true,"duration":12}
|
|
146
|
+
__UJM_TEST__{"event":"result","name":"other-test","passed":false,"duration":34,"error":"expected 1 to be 2"}
|
|
147
|
+
__UJM_TEST__{"event":"skip","name":"x","reason":"manual"}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Then a final summary line:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{"event":"summary","passed":42,"failed":1,"skipped":0,"total":43}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Same protocol as EM (`__EM_TEST__`) and BXM (`__BXM_TEST__`). One marker per framework; same JSON shape.
|
|
157
|
+
|
|
158
|
+
## Discovery
|
|
159
|
+
|
|
160
|
+
- **Framework suites**: glob `<ujm>/dist/test/suites/**/*.js` (resolved from `__dirname/suites` in `runner.js`).
|
|
161
|
+
- **Consumer suites**: glob `<cwd>/test/**/*.js`.
|
|
162
|
+
- **Excluded**: any directory starting with `_` (handy for shared helpers).
|
|
163
|
+
- **Framework boot suites** are excluded when the cwd's `package.json#name` is not `ultimate-jekyll-manager` — they target UJM's fixture site, not the consumer's. Consumers write their own boot tests in `<cwd>/test/boot/`.
|
|
164
|
+
|
|
165
|
+
## Env vars
|
|
166
|
+
|
|
167
|
+
| Env | Set by | Purpose |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| `UJ_TEST_MODE=true` | `npx mgr test` always | Canonical test signal. `Manager.isTesting()` reads this. Use it to short-circuit network calls / prompts / long timers in code that runs during tests. |
|
|
170
|
+
| `UJ_TEST_INTEGRATION=1` | `--integration` flag | Opt-in flag for slower integration tests if your suite has them |
|
|
171
|
+
| `UJ_TEST_BOOT_PROJECT` | Auto-set when UJM tests itself; else manual | Project root the boot runner uses (its `_site/` is the boot target) |
|
|
172
|
+
| `UJ_TEST_BOOT_DIR` | Manual | Absolute override for the `_site/` directory. Wins over `UJ_TEST_BOOT_PROJECT/_site` and `<cwd>/_site` |
|
|
173
|
+
| `UJ_TEST_DEBUG=1` | Manual | Verbose Puppeteer console output piped to the parent stdout |
|
|
174
|
+
|
|
175
|
+
## Puppeteer as a peer-optional dep
|
|
176
|
+
|
|
177
|
+
Puppeteer is a `devDependency` of UJM itself. Consumers don't get it unless they write `page` or `boot` tests. If a consumer tries to run `page`/`boot` tests without puppeteer installed, those layers report as skipped with a clear message — build-layer tests still run.
|
|
178
|
+
|
|
179
|
+
## See also
|
|
180
|
+
|
|
181
|
+
- [test-boot-layer.md](test-boot-layer.md) — deep dive on boot layer (`_site/` discovery, HTTP server, fixture vs consumer)
|
|
182
|
+
- [cross-context-helpers.md](cross-context-helpers.md) — `Manager.isTesting()` / `isDevelopment()` semantics
|
|
183
|
+
- [cli.md](cli.md) — CLI surface, env-var conventions
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultimate-jekyll-manager",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Ultimate Jekyll dependency manager",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"prepare": "node -e \"require('prepare-package')()\"",
|
|
14
14
|
"prepare:watch": "node -e \"require('prepare-package/watch')()\"",
|
|
15
15
|
"wm:prod": "npm uninstall web-manager && npm i web-manager@latest",
|
|
16
|
-
"wm:local": "npm uninstall web-manager && npm i ../web-manager"
|
|
16
|
+
"wm:local": "npm uninstall web-manager && npm i ../web-manager",
|
|
17
|
+
"test": "node ./bin/ultimate-jekyll test"
|
|
17
18
|
},
|
|
18
19
|
"bin": {
|
|
19
20
|
"uj": "bin/ultimate-jekyll",
|
|
@@ -32,7 +33,8 @@
|
|
|
32
33
|
"start": "npx mgr clean && npx mgr setup && bundle exec npm run gulp --",
|
|
33
34
|
"gulp": "gulp --cwd ./ --gulpfile ./node_modules/ultimate-jekyll-manager/dist/gulp/main.js",
|
|
34
35
|
"build": "npx mgr clean && npx mgr setup && UJ_BUILD_MODE=true bundle exec npm run gulp -- build",
|
|
35
|
-
"deploy": "npx mgr deploy"
|
|
36
|
+
"deploy": "npx mgr deploy",
|
|
37
|
+
"test": "npx mgr test"
|
|
36
38
|
},
|
|
37
39
|
"engines": {
|
|
38
40
|
"node": "22",
|
|
@@ -105,7 +107,7 @@
|
|
|
105
107
|
"prettier": "^3.8.3",
|
|
106
108
|
"sass": "^1.99.0",
|
|
107
109
|
"spellchecker": "^3.7.1",
|
|
108
|
-
"web-manager": "^4.1.
|
|
110
|
+
"web-manager": "^4.1.42",
|
|
109
111
|
"webpack": "^5.106.2",
|
|
110
112
|
"wonderful-fetch": "^2.0.5",
|
|
111
113
|
"wonderful-version": "^1.3.2",
|
|
@@ -115,6 +117,7 @@
|
|
|
115
117
|
"gulp": "^5.0.1"
|
|
116
118
|
},
|
|
117
119
|
"devDependencies": {
|
|
118
|
-
"prepare-package": "^2.1.0"
|
|
120
|
+
"prepare-package": "^2.1.0",
|
|
121
|
+
"puppeteer": "^24.43.1"
|
|
119
122
|
}
|
|
120
123
|
}
|