@omega.js/desktop 0.53.0 → 0.54.1
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/README.md +38 -38
- package/dist/cli-run.js +4 -1
- package/dist/cli.js +2 -2
- package/dist/commands/cdp/client.js +1 -1
- package/dist/commands/cdp.js +1 -1
- package/dist/commands/clean.js +2 -3
- package/dist/commands/dev.js +25 -0
- package/dist/commands/lib/ensure-target.js +12 -17
- package/dist/commands/lib/migrate.js +17 -0
- package/dist/commands/logs.js +1 -1
- package/dist/commands/release.js +1 -1
- package/dist/commands/test.js +4 -4
- package/dist/commands/update.js +5 -4
- package/dist/defaults/.github/workflows/build.yml +18 -18
- package/dist/defaults/_.gitignore +0 -2
- package/dist/defaults/_mas/README.md +3 -3
- package/dist/defaults/config/certs/README.md +1 -1
- package/dist/defaults/config/omega.json5 +36 -36
- package/dist/defaults/docs/README.md +3 -3
- package/dist/defaults/gulpfile.js +1 -1
- package/dist/defaults/hooks/build/post.js +1 -1
- package/dist/defaults/hooks/build/pre.js +1 -1
- package/dist/defaults/hooks/notarize/post.js +2 -2
- package/dist/defaults/hooks/release/post.js +1 -1
- package/dist/defaults/hooks/release/pre.js +1 -1
- package/dist/defaults/src/assets/scss/pages/about.scss +1 -1
- package/dist/defaults/src/assets/scss/pages/main.scss +1 -1
- package/dist/defaults/src/assets/scss/pages/settings.scss +1 -1
- package/dist/defaults/src/integrations/context-menu/index.js +11 -11
- package/dist/defaults/src/integrations/menu/index.js +5 -5
- package/dist/defaults/src/integrations/tray/index.js +9 -9
- package/dist/defaults/src/main.js +2 -2
- package/dist/defaults/src/preload.js +1 -1
- package/dist/defaults/test/README.md +3 -3
- package/dist/defaults/test/_init.js +1 -1
- package/dist/gulp/tasks/audit.js +5 -8
- package/dist/lib/restart-manager/index.js +1 -1
- package/dist/lib/restart-manager/install.js +1 -1
- package/dist/lib/restart-manager/protocol.js +1 -1
- package/dist/main.js +4 -3
- package/dist/preload.js +1 -1
- package/dist/test/suites/build/audit.test.js +20 -7
- package/dist/test/suites/build/build-workflow-jobs.test.js +2 -2
- package/dist/test/suites/build/cli.test.js +28 -0
- package/dist/test/suites/build/defaults-em-dash.test.js +22 -0
- package/dist/test/suites/build/defaults-scaffold.test.js +19 -5
- package/dist/test/suites/build/deploy-direct.test.js +7 -5
- package/dist/test/suites/build/deploy-dispatch.test.js +2 -1
- package/dist/test/suites/build/deploy-hook.test.js +4 -2
- package/dist/test/suites/build/dev-verb.test.js +67 -0
- package/dist/test/suites/build/ensure-target.test.js +11 -3
- package/dist/test/suites/build/merge-line-files.test.js +6 -6
- package/dist/test/suites/build/migrate.test.js +29 -0
- package/dist/test/suites/build/project-scripts-deps.test.js +6 -10
- package/dist/test/suites/build/runner-env-write.test.js +73 -0
- package/dist/test/suites/build/runner.test.js +9 -8
- package/dist/test/suites/build/setup-scripts.test.js +27 -0
- package/dist/test/suites/build/validate-config.test.js +13 -2
- package/dist/test/suites/build/verb-logs.test.js +20 -0
- package/dist/test/suites/renderer/window-desktop-surface.test.js +1 -1
- package/dist/utils/build-pipeline.js +4 -4
- package/dist/utils/runner-env.js +13 -28
- package/dist/vendor/config/company.js +46 -14
- package/dist/vendor/config/defaults.js +30 -7
- package/dist/vendor/config/edit.js +25 -3
- package/dist/vendor/config/env-delivery.js +1 -1
- package/dist/vendor/config/env-schema.js +3 -6
- package/dist/vendor/config/env.js +34 -22
- package/dist/vendor/config/index.js +13 -17
- package/dist/vendor/config/load.js +15 -7
- package/dist/vendor/config/repo.js +10 -27
- package/dist/vendor/config/schema-client.js +64 -0
- package/dist/vendor/config/schema-cloud.js +38 -0
- package/dist/vendor/config/schema-manager.js +118 -0
- package/dist/vendor/config/schema-overrides.js +68 -0
- package/dist/vendor/config/schema.js +99 -152
- package/dist/vendor/config/validate.js +97 -77
- package/dist/vendor/devkit/agents-md.js +233 -0
- package/dist/vendor/devkit/attach-log-file.js +15 -1
- package/dist/vendor/devkit/ci-workflows.js +30 -30
- package/dist/vendor/devkit/cli-router.js +13 -7
- package/dist/vendor/devkit/defaults-engine.js +9 -43
- package/dist/vendor/devkit/deploy-snapshot.js +44 -9
- package/dist/vendor/devkit/env-lines.js +183 -0
- package/dist/vendor/devkit/local.js +62 -10
- package/dist/vendor/devkit/lockfile.js +32 -13
- package/dist/vendor/devkit/logger.js +7 -2
- package/dist/vendor/devkit/merge-line-files.js +219 -176
- package/dist/vendor/devkit/omega-bin.js +208 -111
- package/dist/vendor/devkit/preludes/docs-sync.js +52 -0
- package/dist/vendor/devkit/preludes/index.js +1 -0
- package/dist/vendor/devkit/target-picker.js +45 -0
- package/dist/vendor/devkit/test/dashed-files.js +37 -0
- package/dist/vendor/devkit/test/run-verb-under-tee.js +71 -0
- package/dist/vendor/devkit/update.js +15 -15
- package/dist/vendor/devkit/verb-scripts.js +40 -0
- package/dist/vendor/devkit/verbs.js +170 -0
- package/package.json +18 -24
- package/dist/commands/install.js +0 -37
- package/dist/defaults/AGENTS.md +0 -119
- package/dist/defaults/CLAUDE.md +0 -1
- package/dist/vendor/config/env-retired.js +0 -137
- package/dist/vendor/config/retired-keys.js +0 -635
- package/docs/analytics.md +0 -140
- package/docs/app-state.md +0 -92
- package/docs/audit.md +0 -69
- package/docs/auth.md +0 -284
- package/docs/auto-updater.md +0 -243
- package/docs/boot-sequence.md +0 -44
- package/docs/build-system.md +0 -169
- package/docs/cdp-debugging.md +0 -169
- package/docs/common-mistakes.md +0 -21
- package/docs/config-schema.md +0 -120
- package/docs/context-menu.md +0 -112
- package/docs/context.md +0 -81
- package/docs/css.md +0 -84
- package/docs/deep-link.md +0 -186
- package/docs/environment-detection.md +0 -112
- package/docs/fontawesome.md +0 -109
- package/docs/hooks.md +0 -89
- package/docs/icons.md +0 -79
- package/docs/index.md +0 -328
- package/docs/installer-options.md +0 -165
- package/docs/ipc.md +0 -61
- package/docs/lib-modules.md +0 -53
- package/docs/logging.md +0 -227
- package/docs/menu.md +0 -160
- package/docs/releasing.md +0 -239
- package/docs/remote-config.md +0 -118
- package/docs/remote-scripts.md +0 -144
- package/docs/restart-manager.md +0 -144
- package/docs/runner.md +0 -290
- package/docs/sentry.md +0 -97
- package/docs/shared/agent-docs.md +0 -89
- package/docs/shared/analytics.md +0 -612
- package/docs/shared/brands.md +0 -57
- package/docs/shared/breaking-changes.md +0 -917
- package/docs/shared/config.md +0 -1948
- package/docs/shared/deploys.md +0 -341
- package/docs/shared/icons.md +0 -219
- package/docs/shared/local-dev.md +0 -167
- package/docs/shared/logging.md +0 -205
- package/docs/shared/monitoring.md +0 -167
- package/docs/shared/publishing.md +0 -187
- package/docs/shared/rulings.md +0 -34
- package/docs/shared/testing.md +0 -147
- package/docs/shared/theming.md +0 -629
- package/docs/shared/translation.md +0 -342
- package/docs/shared/updates.md +0 -61
- package/docs/signing.md +0 -293
- package/docs/startup.md +0 -142
- package/docs/storage.md +0 -59
- package/docs/templating.md +0 -101
- package/docs/test-boot-layer.md +0 -157
- package/docs/test-framework.md +0 -362
- package/docs/themes.md +0 -149
- package/docs/tooltips.md +0 -99
- package/docs/tray.md +0 -164
- package/docs/usage.md +0 -58
- package/docs/verts.md +0 -62
- package/docs/windows.md +0 -149
|
@@ -122,8 +122,8 @@ module.exports = defineCases({
|
|
|
122
122
|
ctx.expect(decode.run).toContain('if [ -n "${{ secrets.CSC_LINK }}" ]; then');
|
|
123
123
|
ctx.expect(decode.run).toContain('if [ -n "${{ secrets.APPLE_API_KEY }}" ]; then');
|
|
124
124
|
// The standalone verb is gone (#891): the deploy precheck pushes them.
|
|
125
|
-
ctx.expect(decode.run).toContain('No CSC_LINK secret: run omega deploy
|
|
126
|
-
ctx.expect(decode.run).toContain('No APPLE_API_KEY secret: run omega deploy
|
|
125
|
+
ctx.expect(decode.run).toContain('No CSC_LINK secret: run omega deploy at the brand root');
|
|
126
|
+
ctx.expect(decode.run).toContain('No APPLE_API_KEY secret: run omega deploy at the brand root');
|
|
127
127
|
ctx.expect(decode.run).not.toContain('push-secrets');
|
|
128
128
|
ctx.expect(decode.run.match(/exit 1/g).length).toBe(2);
|
|
129
129
|
ctx.expect(decode.run).not.toContain('this build will not be signed');
|
|
@@ -145,6 +145,34 @@ module.exports = defineCases({
|
|
|
145
145
|
}
|
|
146
146
|
},
|
|
147
147
|
},
|
|
148
|
+
{
|
|
149
|
+
name: 'update: --dry-run reaches devkit runUpdate as dryRun, and a bare run installs',
|
|
150
|
+
run: async (ctx) => {
|
|
151
|
+
const devkitUpdate = require('../../../vendor/devkit/update.js');
|
|
152
|
+
const { BOOLEAN_FLAGS } = require(path.join(root, 'dist', 'cli-run.js'));
|
|
153
|
+
const { parseArgv } = require('../../../vendor/devkit/argv.js');
|
|
154
|
+
const commandFile = path.join(root, 'dist', 'commands', 'update.js');
|
|
155
|
+
|
|
156
|
+
// The command destructures runUpdate at load, so the stub lands before a fresh require
|
|
157
|
+
async function run(args) {
|
|
158
|
+
const original = devkitUpdate.runUpdate;
|
|
159
|
+
const seen = [];
|
|
160
|
+
devkitUpdate.runUpdate = async (options) => { seen.push(options); };
|
|
161
|
+
delete require.cache[commandFile];
|
|
162
|
+
try {
|
|
163
|
+
await require(commandFile)(parseArgv(args, { booleans: BOOLEAN_FLAGS }));
|
|
164
|
+
} finally {
|
|
165
|
+
devkitUpdate.runUpdate = original;
|
|
166
|
+
delete require.cache[commandFile];
|
|
167
|
+
}
|
|
168
|
+
ctx.expect(seen.length).toBe(1);
|
|
169
|
+
return seen[0];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
ctx.expect((await run(['update', '--dry-run'])).dryRun).toBe(true);
|
|
173
|
+
ctx.expect(Boolean((await run(['update'])).dryRun)).toBe(false);
|
|
174
|
+
},
|
|
175
|
+
},
|
|
148
176
|
{
|
|
149
177
|
name: 'mirrored aliases: -t routes to test, -d routes to deploy (wave-6 D6)',
|
|
150
178
|
run: (ctx) => {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Every defaults file is copied into a consumer's repo, whose own guard may
|
|
2
|
+
// refuse an em dash (U+2014) at commit time. So no defaults file carries one.
|
|
3
|
+
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const defineCases = require('../../../vendor/devkit/test/define-cases.js');
|
|
6
|
+
const { dashedFiles } = require('../../../vendor/devkit/test/dashed-files.js');
|
|
7
|
+
|
|
8
|
+
const DEFAULTS = path.join(__dirname, '..', '..', '..', 'defaults');
|
|
9
|
+
|
|
10
|
+
module.exports = defineCases({
|
|
11
|
+
type: 'group',
|
|
12
|
+
layer: 'build',
|
|
13
|
+
description: 'defaults tree carries no em dash',
|
|
14
|
+
tests: [
|
|
15
|
+
{
|
|
16
|
+
name: 'no defaults file carries an em dash',
|
|
17
|
+
run: (ctx) => {
|
|
18
|
+
ctx.expect(dashedFiles(DEFAULTS)).toEqual([]);
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
});
|
|
@@ -34,10 +34,11 @@ module.exports = defineCases({
|
|
|
34
34
|
// .env and every verb delivers them.
|
|
35
35
|
ctx.expect(jetpack.exists(path.join(tmp, '.env'))).toBe(false);
|
|
36
36
|
ctx.expect(jetpack.exists(path.join(tmp, '.gitignore'))).toBeTruthy();
|
|
37
|
-
//
|
|
38
|
-
// the
|
|
39
|
-
|
|
40
|
-
ctx.expect(jetpack.read(path.join(tmp, '
|
|
37
|
+
// A standalone project root gets the same AGENTS.md a brand root does:
|
|
38
|
+
// the manager import under Default, its notes under Custom. Claude Code reads
|
|
39
|
+
// AGENTS.md natively, so no CLAUDE.md scaffolds beside it.
|
|
40
|
+
ctx.expect(jetpack.read(path.join(tmp, 'AGENTS.md'))).toBe('<!-- ========== Default Values ========== -->\n@node_modules/@omega.js/manager/AGENTS.md\n\n<!-- ========== Custom Values ========== -->\n');
|
|
41
|
+
ctx.expect(jetpack.exists(path.join(tmp, 'CLAUDE.md'))).toBe(false);
|
|
41
42
|
ctx.expect(jetpack.exists(path.join(tmp, '_mas'))).toBe(false);
|
|
42
43
|
// `_`-prefixed FILENAMES are not archives — test/_init.js ships.
|
|
43
44
|
ctx.expect(jetpack.exists(path.join(tmp, 'test', '_init.js'))).toBeTruthy();
|
|
@@ -213,6 +214,20 @@ module.exports = defineCases({
|
|
|
213
214
|
ctx.expect(jetpack.exists(path.join(targetDir, 'config', 'omega.json5'))).toBe(false);
|
|
214
215
|
},
|
|
215
216
|
},
|
|
217
|
+
{
|
|
218
|
+
name: 'an old-template AGENTS.md converges, keeping the consumer notes under the Custom marker',
|
|
219
|
+
run: async (ctx) => {
|
|
220
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-defaults-'));
|
|
221
|
+
jetpack.write(path.join(tmp, 'AGENTS.md'),
|
|
222
|
+
`${DEFAULT_MARKER}\n# OMEGA Desktop consumer project\nframework guidance\n\n${CUSTOM_MARKER}\n\n## Project-specific notes\n\nAdd anything specific to THIS project here. Edits below this line are preserved across framework re-syncs.\n\nOur deploy needs the VPN up.\n`);
|
|
223
|
+
const warnings = [];
|
|
224
|
+
const applied = await copyDefaults(tmp, { log: () => {}, warn: (m) => warnings.push(m), error: () => {} });
|
|
225
|
+
|
|
226
|
+
ctx.expect(jetpack.read(path.join(tmp, 'AGENTS.md'))).toBe('<!-- ========== Default Values ========== -->\n@node_modules/@omega.js/manager/AGENTS.md\n\n<!-- ========== Custom Values ========== -->\nOur deploy needs the VPN up.\n');
|
|
227
|
+
ctx.expect(applied.merged.includes('AGENTS.md')).toBe(true);
|
|
228
|
+
ctx.expect(warnings.some((m) => m.includes('Converged AGENTS.md'))).toBe(true);
|
|
229
|
+
},
|
|
230
|
+
},
|
|
216
231
|
{
|
|
217
232
|
name: 'brand target scaffolds NO per-target docs (brand doc unification: the brand root is the doc home)',
|
|
218
233
|
run: async (ctx) => {
|
|
@@ -240,7 +255,6 @@ module.exports = defineCases({
|
|
|
240
255
|
// Standalone scaffold first (no brand config yet) — per-target docs land.
|
|
241
256
|
await copyDefaults(targetDir);
|
|
242
257
|
ctx.expect(jetpack.exists(path.join(targetDir, 'AGENTS.md'))).toBeTruthy();
|
|
243
|
-
ctx.expect(jetpack.exists(path.join(targetDir, 'CLAUDE.md'))).toBeTruthy();
|
|
244
258
|
|
|
245
259
|
// Wrap it in a brand monorepo: the next setup sweeps the untouched docs.
|
|
246
260
|
jetpack.write(path.join(tmp, 'brand', 'config', 'omega.json5'), "{ brand: { id: 'acme', name: 'Acme' } }\n");
|
|
@@ -26,10 +26,10 @@ const COMMANDS = path.join(__dirname, '..', '..', '..', 'commands');
|
|
|
26
26
|
const DEPLOY = path.join(COMMANDS, 'deploy.js');
|
|
27
27
|
const WORKFLOW = path.join(__dirname, '..', '..', '..', 'defaults', '.github', 'workflows', 'build.yml');
|
|
28
28
|
|
|
29
|
-
// The scripts every target gets from the scaffold,
|
|
30
|
-
//
|
|
29
|
+
// The scripts every target gets from the scaffold, derived the one way the
|
|
30
|
+
// scaffold derives them: expanding the workflow's command through THESE is what ties
|
|
31
31
|
// the runner's step to the verb this laptop runs.
|
|
32
|
-
const SCRIPTS = require(path.join(__dirname, '..', '..', '..', '..', 'package.json'))
|
|
32
|
+
const SCRIPTS = require('../../../vendor/devkit/verb-scripts.js').projectScripts(require(path.join(__dirname, '..', '..', '..', '..', 'package.json')));
|
|
33
33
|
|
|
34
34
|
const { directPlatform } = require(DEPLOY);
|
|
35
35
|
|
|
@@ -147,6 +147,7 @@ module.exports = defineCases({
|
|
|
147
147
|
const resolved = require.resolve(DEPLOY);
|
|
148
148
|
const cached = require.cache[resolved];
|
|
149
149
|
delete require.cache[resolved];
|
|
150
|
+
const restoreTee = attachLogFile.mark();
|
|
150
151
|
|
|
151
152
|
try {
|
|
152
153
|
const deploy = require(resolved);
|
|
@@ -159,7 +160,7 @@ module.exports = defineCases({
|
|
|
159
160
|
ctx.expect(ran).toEqual(['ensure-target']);
|
|
160
161
|
} finally {
|
|
161
162
|
// The verb tees this process' writers now (#873): hand them back.
|
|
162
|
-
|
|
163
|
+
restoreTee();
|
|
163
164
|
for (const restore of restores) restore();
|
|
164
165
|
if (cached) require.cache[resolved] = cached;
|
|
165
166
|
else delete require.cache[resolved];
|
|
@@ -206,6 +207,7 @@ module.exports = defineCases({
|
|
|
206
207
|
const resolved = require.resolve(DEPLOY);
|
|
207
208
|
const cached = require.cache[resolved];
|
|
208
209
|
delete require.cache[resolved];
|
|
210
|
+
const restoreTee = attachLogFile.mark();
|
|
209
211
|
|
|
210
212
|
try {
|
|
211
213
|
const deploy = require(resolved);
|
|
@@ -229,7 +231,7 @@ module.exports = defineCases({
|
|
|
229
231
|
ctx.expect(script.split(' ').filter((word) => word.startsWith('--'))).toEqual(['--local']);
|
|
230
232
|
} finally {
|
|
231
233
|
// The verb tees this process' writers now (#873): hand them back.
|
|
232
|
-
|
|
234
|
+
restoreTee();
|
|
233
235
|
deployRecord.recordDeploy = recordDeploy;
|
|
234
236
|
for (const restore of restores) restore();
|
|
235
237
|
if (cached) require.cache[resolved] = cached;
|
|
@@ -108,6 +108,7 @@ async function runRelease(follower, options = {}, token = {}) {
|
|
|
108
108
|
else process.env.GH_TOKEN = envToken;
|
|
109
109
|
process.chdir(targetDir);
|
|
110
110
|
delete require.cache[require.resolve(RELEASE)];
|
|
111
|
+
const restoreTee = attachLogFile.mark();
|
|
111
112
|
|
|
112
113
|
let error = null;
|
|
113
114
|
try {
|
|
@@ -117,7 +118,7 @@ async function runRelease(follower, options = {}, token = {}) {
|
|
|
117
118
|
} finally {
|
|
118
119
|
// The verb tees this process' writers: hand them back before the next
|
|
119
120
|
// suite prints through a fixture that is about to be gone.
|
|
120
|
-
|
|
121
|
+
restoreTee();
|
|
121
122
|
console.log = previousLog;
|
|
122
123
|
process.chdir(previousCwd);
|
|
123
124
|
if (previousToken === undefined) delete process.env.GH_TOKEN;
|
|
@@ -69,6 +69,7 @@ async function runDeploy(options) {
|
|
|
69
69
|
const origCwd = process.cwd();
|
|
70
70
|
|
|
71
71
|
delete require.cache[resolved];
|
|
72
|
+
const restoreTee = attachLogFile.mark();
|
|
72
73
|
global.__omegaDeployHookRan = ran;
|
|
73
74
|
|
|
74
75
|
try {
|
|
@@ -80,7 +81,7 @@ async function runDeploy(options) {
|
|
|
80
81
|
return ran;
|
|
81
82
|
} finally {
|
|
82
83
|
// The verb tees this process' writers now (#873): hand them back.
|
|
83
|
-
|
|
84
|
+
restoreTee();
|
|
84
85
|
process.chdir(origCwd);
|
|
85
86
|
delete global.__omegaDeployHookRan;
|
|
86
87
|
for (const restore of restores) restore();
|
|
@@ -116,6 +117,7 @@ async function runDriftedDeploy() {
|
|
|
116
117
|
const origCwd = process.cwd();
|
|
117
118
|
|
|
118
119
|
delete require.cache[resolved];
|
|
120
|
+
const restoreTee = attachLogFile.mark();
|
|
119
121
|
|
|
120
122
|
try {
|
|
121
123
|
const deploy = require(resolved);
|
|
@@ -124,7 +126,7 @@ async function runDriftedDeploy() {
|
|
|
124
126
|
return ran;
|
|
125
127
|
} finally {
|
|
126
128
|
// The verb tees this process' writers now (#873): hand them back.
|
|
127
|
-
|
|
129
|
+
restoreTee();
|
|
128
130
|
process.chdir(origCwd);
|
|
129
131
|
for (const restore of restores) restore();
|
|
130
132
|
if (cached) require.cache[resolved] = cached;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Build-layer tests for the `dev` verb, what the target's `start` script runs:
|
|
2
|
+
// clean, then the gulp default task (build, then launch electron), with the
|
|
3
|
+
// `--` flags it was given forwarded to the gulp lane. No build-mode flag, and
|
|
4
|
+
// never a shell-out back to `npm start` (that script IS this verb).
|
|
5
|
+
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const defineCases = require('../../../vendor/devkit/test/define-cases.js');
|
|
9
|
+
|
|
10
|
+
const SRC = path.join(__dirname, '..', '..', '..');
|
|
11
|
+
const pipeline = require(path.join(SRC, 'utils', 'build-pipeline.js'));
|
|
12
|
+
const dev = require(path.join(SRC, 'commands', 'dev.js'));
|
|
13
|
+
|
|
14
|
+
const stepsOf = (plan) => plan.steps.map((s) => (s.task ? `${s.type}:${s.task}` : s.type));
|
|
15
|
+
|
|
16
|
+
module.exports = defineCases({
|
|
17
|
+
type: 'suite',
|
|
18
|
+
layer: 'build',
|
|
19
|
+
description: 'dev verb: clean, then the gulp default task',
|
|
20
|
+
tests: [
|
|
21
|
+
{
|
|
22
|
+
name: 'dev: clean → gulp default, no build-mode flag',
|
|
23
|
+
run: (ctx) => {
|
|
24
|
+
const plan = dev.plan({}, []);
|
|
25
|
+
ctx.expect(stepsOf(plan)).toEqual(['clean', 'gulp:default']);
|
|
26
|
+
ctx.expect(plan.env.OMEGA_BUILD_MODE).toBe(undefined);
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'dev forwards its `--` flags to the gulp lane (`npm start -- --remote-debugging-port=9222`)',
|
|
31
|
+
run: (ctx) => {
|
|
32
|
+
const plan = dev.plan({}, ['dev', '--remote-debugging-port=9222', 'stray', '--debug']);
|
|
33
|
+
ctx.expect(plan.steps[1].args).toEqual(['--remote-debugging-port=9222', '--debug']);
|
|
34
|
+
ctx.expect(pipeline.gulpCommand('default', plan.steps[1].args))
|
|
35
|
+
.toBe('npm run gulp -- default --remote-debugging-port=9222 --debug');
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'runPipeline runs the dev plan in order and leaves the build-mode flag unset',
|
|
40
|
+
run: async (ctx) => {
|
|
41
|
+
const log = [];
|
|
42
|
+
const record = (type) => (options, step) => { log.push(step.task ? `${type}:${step.task}` : type); };
|
|
43
|
+
const previous = process.env.OMEGA_BUILD_MODE;
|
|
44
|
+
delete process.env.OMEGA_BUILD_MODE;
|
|
45
|
+
try {
|
|
46
|
+
await pipeline.runPipeline(dev.plan({}, []), {}, { clean: record('clean'), gulp: record('gulp') });
|
|
47
|
+
ctx.expect(process.env.OMEGA_BUILD_MODE).toBe(undefined);
|
|
48
|
+
} finally {
|
|
49
|
+
if (previous !== undefined) process.env.OMEGA_BUILD_MODE = previous;
|
|
50
|
+
}
|
|
51
|
+
ctx.expect(log).toEqual(['clean', 'gulp:default']);
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'the CLI answers dev and its aliases, and the verb never shells back to `npm start`',
|
|
56
|
+
run: (ctx) => {
|
|
57
|
+
const { aliases } = require(path.join(SRC, 'cli.js')).config;
|
|
58
|
+
ctx.expect(aliases.dev).toEqual(['serve', 'start', '--dev']);
|
|
59
|
+
|
|
60
|
+
const source = fs.readFileSync(path.join(SRC, 'commands', 'dev.js'), 'utf8')
|
|
61
|
+
.replace(/\/\/[^\n]*/g, '')
|
|
62
|
+
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
63
|
+
ctx.expect(/npm (run )?start/.test(source)).toBe(false);
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
});
|
|
@@ -67,7 +67,7 @@ module.exports = defineCases({
|
|
|
67
67
|
},
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
|
-
name: 'refuses a workspace root, loudly,
|
|
70
|
+
name: 'refuses a workspace root, loudly, leaving its AGENTS.md and .gitignore byte-identical (#699, #973)',
|
|
71
71
|
run: async (ctx) => {
|
|
72
72
|
// The accident: `omega deploy` at a workspace root scaffolded a whole
|
|
73
73
|
// desktop target into it — gulpfile, src/, hooks/, workflows, rewritten
|
|
@@ -78,6 +78,12 @@ module.exports = defineCases({
|
|
|
78
78
|
manifest.workspaces = ['packages/*'];
|
|
79
79
|
jetpack.write(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
80
80
|
const before = jetpack.read(manifestPath);
|
|
81
|
+
// A root's hand-authored AGENTS.md and .gitignore are what the marker
|
|
82
|
+
// merge rewrites in place: `#` headings and blank lines are its comments.
|
|
83
|
+
const agentsDoc = '# Monorepo\n\n## HARD RULES\n\n1. Rule one.\n';
|
|
84
|
+
const ignoreFile = '# Dependencies\nnode_modules/\n\n# Scratch\n.temp/\n';
|
|
85
|
+
jetpack.write(path.join(tmp, 'AGENTS.md'), agentsDoc);
|
|
86
|
+
jetpack.write(path.join(tmp, '.gitignore'), ignoreFile);
|
|
81
87
|
|
|
82
88
|
try {
|
|
83
89
|
let refusal = null;
|
|
@@ -92,9 +98,11 @@ module.exports = defineCases({
|
|
|
92
98
|
ctx.expect(refusal.message).toMatch(/declares "workspaces"/);
|
|
93
99
|
ctx.expect(refusal.message.includes(tmp)).toBe(true);
|
|
94
100
|
|
|
95
|
-
// Nothing scaffolded, and
|
|
96
|
-
ctx.expect(jetpack.list(tmp)).toEqual(['package.json']);
|
|
101
|
+
// Nothing scaffolded, and every root file is byte-identical.
|
|
102
|
+
ctx.expect(jetpack.list(tmp).sort()).toEqual(['.gitignore', 'AGENTS.md', 'package.json']);
|
|
97
103
|
ctx.expect(jetpack.read(manifestPath)).toBe(before);
|
|
104
|
+
ctx.expect(jetpack.read(path.join(tmp, 'AGENTS.md'))).toBe(agentsDoc);
|
|
105
|
+
ctx.expect(jetpack.read(path.join(tmp, '.gitignore'))).toBe(ignoreFile);
|
|
98
106
|
} finally {
|
|
99
107
|
fs.rmSync(tmp, { recursive: true, force: true });
|
|
100
108
|
}
|
|
@@ -222,17 +222,17 @@ ${CUSTOM_MARKER}
|
|
|
222
222
|
},
|
|
223
223
|
},
|
|
224
224
|
{
|
|
225
|
-
name: 'normalizeEnvLine: empty value
|
|
225
|
+
name: 'normalizeEnvLine: an empty value becomes KEY=""',
|
|
226
226
|
run: (ctx) => {
|
|
227
|
-
ctx.expect(normalizeEnvLine('KEY=')).toBe('KEY=');
|
|
228
|
-
ctx.expect(normalizeEnvLine('KEY= ')).toBe('KEY=');
|
|
227
|
+
ctx.expect(normalizeEnvLine('KEY=')).toBe('KEY=""');
|
|
228
|
+
ctx.expect(normalizeEnvLine('KEY= ')).toBe('KEY=""');
|
|
229
229
|
},
|
|
230
230
|
},
|
|
231
231
|
{
|
|
232
|
-
name: 'normalizeEnvLine:
|
|
232
|
+
name: 'normalizeEnvLine: keeps embedded quotes and backslashes as dotenv reads them',
|
|
233
233
|
run: (ctx) => {
|
|
234
|
-
ctx.expect(normalizeEnvLine('KEY=he said "hi"')).toBe('KEY="he said
|
|
235
|
-
ctx.expect(normalizeEnvLine('KEY=back\\slash')).toBe('KEY="back
|
|
234
|
+
ctx.expect(normalizeEnvLine('KEY=he said "hi"')).toBe('KEY="he said "hi""');
|
|
235
|
+
ctx.expect(normalizeEnvLine('KEY=back\\slash')).toBe('KEY="back\\slash"');
|
|
236
236
|
},
|
|
237
237
|
},
|
|
238
238
|
{
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// migrateTarget: the desktop leg of the brand root's `omega migrate`. Desktop
|
|
2
|
+
// carries no legacy move today, yet exposes the same entry as every framework,
|
|
3
|
+
// so the manager's walk never special-cases a framework name.
|
|
4
|
+
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
|
|
9
|
+
const SRC = path.join(__dirname, '..', '..', '..');
|
|
10
|
+
const { migrateTarget } = require(path.join(SRC, 'commands', 'lib', 'migrate.js'));
|
|
11
|
+
const defineCases = require('../../../vendor/devkit/test/define-cases.js');
|
|
12
|
+
|
|
13
|
+
module.exports = defineCases({
|
|
14
|
+
type: 'group',
|
|
15
|
+
layer: 'build',
|
|
16
|
+
description: 'migrateTarget: the desktop leg answers the shared shape, empty',
|
|
17
|
+
tests: [
|
|
18
|
+
{
|
|
19
|
+
name: 'report mode and execute both answer three empty lists',
|
|
20
|
+
run: (ctx) => {
|
|
21
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-migrate-'));
|
|
22
|
+
|
|
23
|
+
ctx.expect(migrateTarget(tmp)).toEqual({ due: [], changed: [], errors: [] });
|
|
24
|
+
ctx.expect(migrateTarget(tmp, { execute: true })).toEqual({ due: [], changed: [], errors: [] });
|
|
25
|
+
ctx.expect(fs.readdirSync(tmp)).toEqual([]);
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
});
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const fs = require('fs');
|
|
15
15
|
const defineCases = require('../../../vendor/devkit/test/define-cases.js');
|
|
16
|
+
const { projectScripts } = require('../../../vendor/devkit/verb-scripts.js');
|
|
16
17
|
|
|
17
18
|
module.exports = defineCases({
|
|
18
19
|
type: 'suite',
|
|
@@ -26,7 +27,7 @@ module.exports = defineCases({
|
|
|
26
27
|
const peers = pkg.peerDependencies || {};
|
|
27
28
|
|
|
28
29
|
const tools = new Set();
|
|
29
|
-
for (const script of Object.values(pkg
|
|
30
|
+
for (const script of Object.values(projectScripts(pkg))) {
|
|
30
31
|
for (const match of String(script).matchAll(/npx\s+([a-z0-9@/_-]+)/g)) {
|
|
31
32
|
const tool = match[1];
|
|
32
33
|
if (tool !== 'omega' && !tool.startsWith('@omega.js/')) {
|
|
@@ -44,7 +45,7 @@ module.exports = defineCases({
|
|
|
44
45
|
name: 'the build-mode env flags live in the CLI verbs, not in the scaffolded scripts',
|
|
45
46
|
run: (ctx) => {
|
|
46
47
|
const pkg = require(path.join(__dirname, '..', '..', '..', '..', 'package.json'));
|
|
47
|
-
const scripts = pkg
|
|
48
|
+
const scripts = projectScripts(pkg);
|
|
48
49
|
|
|
49
50
|
for (const script of Object.values(scripts)) {
|
|
50
51
|
ctx.expect(String(script).includes('cross-env')).toBe(false);
|
|
@@ -58,7 +59,9 @@ module.exports = defineCases({
|
|
|
58
59
|
ctx.expect(scripts.build).toBe('omega build');
|
|
59
60
|
ctx.expect(scripts.package).toBe('omega package');
|
|
60
61
|
ctx.expect(scripts['package:quick']).toBe('omega package --quick');
|
|
61
|
-
|
|
62
|
+
// A single-target command is the CLI's, reached from the brand root, never a script
|
|
63
|
+
ctx.expect(scripts.publish).toBe(undefined);
|
|
64
|
+
ctx.expect(scripts.release).toBe(undefined);
|
|
62
65
|
ctx.expect(scripts['release:local']).toBe('omega publish --local');
|
|
63
66
|
},
|
|
64
67
|
},
|
|
@@ -79,12 +82,5 @@ module.exports = defineCases({
|
|
|
79
82
|
ctx.expect(source.includes('cross-env')).toBe(false);
|
|
80
83
|
},
|
|
81
84
|
},
|
|
82
|
-
{
|
|
83
|
-
name: 'ensure-target syncs projectScripts unconditionally — consumers heal on the next verb',
|
|
84
|
-
run: (ctx) => {
|
|
85
|
-
const source = fs.readFileSync(path.join(__dirname, '..', '..', '..', 'commands', 'lib', 'ensure-target.js'), 'utf8');
|
|
86
|
-
ctx.expect(/project\.scripts\[key\] = package\.projectScripts\[key\]/.test(source)).toBe(true);
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
85
|
],
|
|
90
86
|
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// runner-env-write tests: the box .env writer rewrites a key in place, one line
|
|
2
|
+
// per key, and every case runs against its own temp home, never the box's.
|
|
3
|
+
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
const jetpack = require('fs-jetpack');
|
|
8
|
+
const runnerEnv = require('../../../utils/runner-env.js');
|
|
9
|
+
const defineCases = require('../../../vendor/devkit/test/define-cases.js');
|
|
10
|
+
|
|
11
|
+
module.exports = defineCases({
|
|
12
|
+
type: 'group',
|
|
13
|
+
layer: 'build',
|
|
14
|
+
description: 'runner-env writeRunnerEnvValues',
|
|
15
|
+
tests: [
|
|
16
|
+
{
|
|
17
|
+
name: 'a write replaces every line assigning the key, a placeholder above a set line included',
|
|
18
|
+
run: (ctx) => {
|
|
19
|
+
// dotenv reads a key's LAST line, so a later line left behind would
|
|
20
|
+
// win over the new value and the read-back would refuse the write.
|
|
21
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'omega-runner-home-'));
|
|
22
|
+
try {
|
|
23
|
+
jetpack.write(path.join(home, '.env'), '# GH_TOKEN=""\nGH_TOKEN="old"\nSIGNTOOL_PATH="s"\n');
|
|
24
|
+
runnerEnv.writeRunnerEnvValues(home, { GH_TOKEN: 'new' });
|
|
25
|
+
|
|
26
|
+
const written = jetpack.read(path.join(home, '.env'));
|
|
27
|
+
ctx.expect((written.match(/^\s*#?\s*GH_TOKEN\s*=/gm) || []).length).toBe(1);
|
|
28
|
+
ctx.expect(written).toContain('SIGNTOOL_PATH="s"');
|
|
29
|
+
const back = {};
|
|
30
|
+
runnerEnv.loadRunnerEnv({ home, env: back });
|
|
31
|
+
ctx.expect(back.GH_TOKEN).toBe('new');
|
|
32
|
+
} finally {
|
|
33
|
+
jetpack.remove(home);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'a write replaces a later export or indented assignment of the key',
|
|
39
|
+
run: (ctx) => {
|
|
40
|
+
for (const later of ['export GH_TOKEN="b"', ' GH_TOKEN="b"']) {
|
|
41
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'omega-runner-home-'));
|
|
42
|
+
try {
|
|
43
|
+
jetpack.write(path.join(home, '.env'), `GH_TOKEN="a"\n${later}\n`);
|
|
44
|
+
runnerEnv.writeRunnerEnvValues(home, { GH_TOKEN: 'new' });
|
|
45
|
+
|
|
46
|
+
const written = jetpack.read(path.join(home, '.env'));
|
|
47
|
+
ctx.expect((written.match(/^\s*(?:export\s+)?GH_TOKEN\s*=/gm) || []).length).toBe(1);
|
|
48
|
+
const back = {};
|
|
49
|
+
runnerEnv.loadRunnerEnv({ home, env: back });
|
|
50
|
+
ctx.expect(back.GH_TOKEN).toBe('new');
|
|
51
|
+
} finally {
|
|
52
|
+
jetpack.remove(home);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'a write replaces a multi-line quoted value whole',
|
|
59
|
+
run: (ctx) => {
|
|
60
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'omega-runner-home-'));
|
|
61
|
+
try {
|
|
62
|
+
jetpack.write(path.join(home, '.env'), 'GH_TOKEN="first\nsecond"\nSIGNTOOL_PATH="s"\n');
|
|
63
|
+
runnerEnv.writeRunnerEnvValues(home, { GH_TOKEN: 'new' });
|
|
64
|
+
|
|
65
|
+
const written = jetpack.read(path.join(home, '.env'));
|
|
66
|
+
ctx.expect(written).toBe('GH_TOKEN="new"\nSIGNTOOL_PATH="s"\n');
|
|
67
|
+
} finally {
|
|
68
|
+
jetpack.remove(home);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
});
|
|
@@ -1279,16 +1279,17 @@ module.exports = defineCases({
|
|
|
1279
1279
|
ctx.expect(back.WIN_CSC_KEY_PASSWORD).toBe('p in spaces #1');
|
|
1280
1280
|
ctx.expect(back.NEW_KEY).toBe('appended');
|
|
1281
1281
|
|
|
1282
|
-
// A
|
|
1283
|
-
//
|
|
1282
|
+
// A `"` is written raw and reads back whole. A quote followed by # would
|
|
1283
|
+
// not, so it is refused naming the key, never the value, file untouched.
|
|
1284
|
+
runnerEnv.writeRunnerEnvValues(home, { WIN_CSC_KEY_PASSWORD: 'p in "quotes"' });
|
|
1285
|
+
delete back.WIN_CSC_KEY_PASSWORD;
|
|
1286
|
+
runnerEnv.loadRunnerEnv({ home, env: back });
|
|
1287
|
+
ctx.expect(back.WIN_CSC_KEY_PASSWORD).toBe('p in "quotes"');
|
|
1284
1288
|
let refused;
|
|
1285
|
-
try {
|
|
1286
|
-
runnerEnv.writeRunnerEnvValues(home, { WIN_CSC_KEY_PASSWORD: 'p in "quotes"' });
|
|
1287
|
-
} catch (e) { refused = e; }
|
|
1288
|
-
ctx.expect(refused).toBeDefined();
|
|
1289
|
+
try { runnerEnv.writeRunnerEnvValues(home, { WIN_CSC_KEY_PASSWORD: 'p "x" #tail' }); } catch (e) { refused = e; }
|
|
1289
1290
|
ctx.expect(refused.message).toContain('WIN_CSC_KEY_PASSWORD');
|
|
1290
|
-
ctx.expect(refused.message).toContain('
|
|
1291
|
-
ctx.expect(jetpack.read(path.join(home, '.env'))).toContain('WIN_CSC_KEY_PASSWORD="p in
|
|
1291
|
+
ctx.expect(refused.message).not.toContain('#tail');
|
|
1292
|
+
ctx.expect(jetpack.read(path.join(home, '.env'))).toContain('WIN_CSC_KEY_PASSWORD="p in "quotes""');
|
|
1292
1293
|
} finally {
|
|
1293
1294
|
jetpack.remove(home);
|
|
1294
1295
|
}
|
|
@@ -12,6 +12,7 @@ const path = require('path');
|
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const os = require('os');
|
|
14
14
|
const defineCases = require('../../../vendor/devkit/test/define-cases.js');
|
|
15
|
+
const { verbScripts } = require('../../../vendor/devkit/verb-scripts.js');
|
|
15
16
|
|
|
16
17
|
const SRC = path.join(__dirname, '..', '..', '..');
|
|
17
18
|
const SETUP_PATH = path.join(SRC, 'commands', 'lib', 'ensure-target.js');
|
|
@@ -134,6 +135,32 @@ module.exports = defineCases({
|
|
|
134
135
|
}
|
|
135
136
|
},
|
|
136
137
|
},
|
|
138
|
+
{
|
|
139
|
+
name: 'the verb scripts derive from the verb table, `start` among them',
|
|
140
|
+
run: async (ctx) => {
|
|
141
|
+
const tmp = stageProject(CONSUMER_PKG);
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
await inProject(tmp, async (setup) => {
|
|
145
|
+
setup.setupScripts();
|
|
146
|
+
|
|
147
|
+
const { scripts } = JSON.parse(fs.readFileSync(path.join(tmp, 'package.json'), 'utf8'));
|
|
148
|
+
const derived = verbScripts('@omega.js/desktop');
|
|
149
|
+
for (const [verb, command] of Object.entries(derived)) {
|
|
150
|
+
ctx.expect(scripts[verb]).toBe(command);
|
|
151
|
+
}
|
|
152
|
+
ctx.expect(scripts.start).toBe('omega dev');
|
|
153
|
+
ctx.expect(scripts.gulp).toBe('gulp');
|
|
154
|
+
|
|
155
|
+
// No verb script is typed by hand: the manifest declares only what the table cannot derive
|
|
156
|
+
const declared = require(path.join(SRC, '..', 'package.json')).projectScripts;
|
|
157
|
+
ctx.expect(Object.keys(declared).filter((key) => key in derived)).toEqual([]);
|
|
158
|
+
});
|
|
159
|
+
} finally {
|
|
160
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
},
|
|
137
164
|
{
|
|
138
165
|
name: 'a target still carrying the `npx omega` spelling heals to the bare verb (#748)',
|
|
139
166
|
run: async (ctx) => {
|
|
@@ -48,8 +48,8 @@ module.exports = defineCases({
|
|
|
48
48
|
name: 'desktop refinements apply only with target: desktop',
|
|
49
49
|
run: (ctx) => {
|
|
50
50
|
const cfg = { ...VALID, startup: { mode: 'tray-only' } };
|
|
51
|
-
// Without a target, startup.mode is
|
|
52
|
-
ctx.expect(validateConfig(cfg).errors).toEqual([]);
|
|
51
|
+
// Without a target, startup.mode is a key nobody declared: the strict schema names it.
|
|
52
|
+
ctx.expect(validateConfig(cfg).errors.map((e) => e.split(' ')[0])).toEqual(['config.startup.mode']);
|
|
53
53
|
// With the desktop target, the enum refinement fires.
|
|
54
54
|
const { errors } = validateConfig(cfg, { target: 'desktop' });
|
|
55
55
|
ctx.expect(errors.some((e) => e.includes('startup.mode') && e.includes('not allowed'))).toBe(true);
|
|
@@ -70,6 +70,17 @@ module.exports = defineCases({
|
|
|
70
70
|
ctx.expect(errors.some((e) => e.includes('looks like a secret'))).toBe(true);
|
|
71
71
|
},
|
|
72
72
|
},
|
|
73
|
+
{
|
|
74
|
+
// The boot (main.js) and the audit validate a BAKED config, which carries
|
|
75
|
+
// the build facts; only `decorated: true` declares them.
|
|
76
|
+
name: 'a baked config passes as decorated, and its build facts fail an authored load',
|
|
77
|
+
run: (ctx) => {
|
|
78
|
+
const baked = { ...VALID, runtime: 'electron', environment: 'production', version: '1.0.0', buildTime: 1, target: 'desktop' };
|
|
79
|
+
ctx.expect(validateConfig(baked, { target: 'desktop', decorated: true }).errors).toEqual([]);
|
|
80
|
+
const authored = validateConfig(baked, { target: 'desktop' }).errors.map((e) => e.split(' ')[0]);
|
|
81
|
+
ctx.expect(authored).toEqual(['config.runtime', 'config.environment', 'config.version', 'config.buildTime', 'config.target']);
|
|
82
|
+
},
|
|
83
|
+
},
|
|
73
84
|
{
|
|
74
85
|
name: 'formatErrors renders a numbered block',
|
|
75
86
|
run: (ctx) => {
|
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
const path = require('path');
|
|
11
11
|
const fs = require('fs');
|
|
12
12
|
const defineCases = require('../../../vendor/devkit/test/define-cases.js');
|
|
13
|
+
const { runTestVerbUnderOuterTee } = require('../../../vendor/devkit/test/run-verb-under-tee.js');
|
|
14
|
+
|
|
15
|
+
const COMMANDS = path.join(__dirname, '..', '..', '..', 'commands');
|
|
16
|
+
const PREFIX = 'desktop-test-verb-';
|
|
13
17
|
|
|
14
18
|
module.exports = defineCases({
|
|
15
19
|
type: 'suite',
|
|
@@ -39,5 +43,21 @@ module.exports = defineCases({
|
|
|
39
43
|
ctx.expect(line).toBe(marker);
|
|
40
44
|
},
|
|
41
45
|
},
|
|
46
|
+
{
|
|
47
|
+
// The verb takes off only the layer its own attach pushed: a declined
|
|
48
|
+
// attach pushes none, and a blind pop would eat the tee underneath.
|
|
49
|
+
name: 'a verb whose attach declined leaves the outer tee receiving (no-match exit)',
|
|
50
|
+
run: async (ctx) => {
|
|
51
|
+
const { outer } = await runTestVerbUnderOuterTee({ commands: COMMANDS, prefix: PREFIX, positionals: ['project:does-not-exist'] });
|
|
52
|
+
ctx.expect(outer.includes('after the verb')).toBe(true);
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: 'a verb whose attach declined leaves the outer tee receiving (green exit)',
|
|
57
|
+
run: async (ctx) => {
|
|
58
|
+
const { outer } = await runTestVerbUnderOuterTee({ commands: COMMANDS, prefix: PREFIX, positionals: [] });
|
|
59
|
+
ctx.expect(outer.includes('after the verb')).toBe(true);
|
|
60
|
+
},
|
|
61
|
+
},
|
|
42
62
|
],
|
|
43
63
|
});
|
|
@@ -49,7 +49,7 @@ module.exports = defineCases({
|
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
// wave-5 F4: ipc.on used to return ipcRenderer (stripped to a useless
|
|
52
|
-
// object across the contextBridge) — docs/ipc.md promises an unsubscribe fn.
|
|
52
|
+
// object across the contextBridge) — docs/desktop/ipc.md promises an unsubscribe fn.
|
|
53
53
|
name: 'ipc.on returns an unsubscribe function (docs contract)',
|
|
54
54
|
run: (ctx) => {
|
|
55
55
|
const off = window.desktop.ipc.on('omega-test:noop-channel', () => {});
|