@omega.js/desktop 0.52.0 → 0.53.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.
Files changed (273) hide show
  1. package/README.md +17 -12
  2. package/dist/assets/css/core/_initialize.scss +1 -1
  3. package/dist/assets/js/core/app-shell.js +14 -15
  4. package/dist/assets/themes/_template/_theme.js +6 -6
  5. package/dist/assets/themes/base/_includes/global/sections/account.html +4 -4
  6. package/dist/assets/themes/base/_includes/global/sections/app-sidebar.html +5 -5
  7. package/dist/assets/themes/base/_layouts/frontend/pages/account/index.html +3 -3
  8. package/dist/assets/themes/base/_layouts/frontend/pages/alternatives/index.html +1 -1
  9. package/dist/assets/themes/base/_layouts/frontend/pages/blog/tags/tag.html +1 -1
  10. package/dist/assets/themes/base/_layouts/frontend/pages/payment/confirmation.html +1 -1
  11. package/dist/assets/themes/base/_sections/marketing/newsletter-cta/section.js +2 -3
  12. package/dist/assets/themes/base/_sections/verts/unit/section.html +1 -1
  13. package/dist/assets/themes/base/_sections/verts/unit/section.js +3 -4
  14. package/dist/assets/themes/base/_theme.js +4 -3
  15. package/dist/assets/themes/bootstrap/_theme.js +2 -2
  16. package/dist/assets/themes/bootstrap/overrides/_links.scss +1 -1
  17. package/dist/assets/themes/classy/_theme.js +8 -6
  18. package/dist/assets/themes/classy/css/marketing/_sections.scss +1 -2
  19. package/dist/assets/themes/classy/js/hero-demo-form.js +3 -2
  20. package/dist/assets/themes/neobrutalism/_theme.js +5 -5
  21. package/dist/assets/themes/neobrutalism/js/pages/test/libraries/layers/index.js +1 -1
  22. package/dist/assets/themes/newsflash/_theme.js +6 -6
  23. package/dist/assets/themes/newsflash/js/pages/test/libraries/layers/index.js +1 -1
  24. package/dist/build.js +87 -111
  25. package/dist/cli.js +1 -1
  26. package/dist/commands/build.js +2 -2
  27. package/dist/commands/cdp/capture.js +2 -2
  28. package/dist/commands/cdp/quit.js +2 -2
  29. package/dist/commands/cdp/relaunch.js +2 -2
  30. package/dist/commands/cdp/theme.js +1 -1
  31. package/dist/commands/clean.js +2 -2
  32. package/dist/commands/deploy.js +4 -4
  33. package/dist/commands/finalize-release.js +4 -4
  34. package/dist/commands/install.js +3 -3
  35. package/dist/commands/launch.js +2 -2
  36. package/dist/commands/lib/deploy-precheck.js +3 -3
  37. package/dist/commands/lib/ensure-target.js +6 -6
  38. package/dist/commands/package.js +2 -2
  39. package/dist/commands/publish.js +2 -2
  40. package/dist/commands/release.js +3 -3
  41. package/dist/commands/runner.js +11 -11
  42. package/dist/commands/sign-windows.js +5 -5
  43. package/dist/commands/test.js +4 -4
  44. package/dist/commands/update.js +2 -2
  45. package/dist/commands/validate-certs.js +4 -4
  46. package/dist/commands/version.js +3 -3
  47. package/dist/defaults/AGENTS.md +17 -8
  48. package/dist/defaults/config/omega.json5 +7 -7
  49. package/dist/defaults/hooks/build/post.js +1 -1
  50. package/dist/defaults/hooks/build/pre.js +1 -1
  51. package/dist/defaults/hooks/deploy/pre.js +1 -1
  52. package/dist/defaults/hooks/release/post.js +1 -1
  53. package/dist/defaults/hooks/release/pre.js +1 -1
  54. package/dist/defaults/src/assets/js/components/about/index.js +3 -5
  55. package/dist/defaults/src/assets/js/components/main/index.js +3 -5
  56. package/dist/defaults/src/assets/js/components/settings/index.js +3 -5
  57. package/dist/defaults/src/integrations/context-menu/index.js +2 -2
  58. package/dist/defaults/src/integrations/menu/index.js +3 -3
  59. package/dist/defaults/src/integrations/tray/index.js +3 -3
  60. package/dist/defaults/src/main.js +3 -5
  61. package/dist/defaults/src/preload.js +3 -5
  62. package/dist/defaults/test/README.md +2 -2
  63. package/dist/gulp/main.js +9 -10
  64. package/dist/gulp/tasks/audit.js +7 -7
  65. package/dist/gulp/tasks/build-config.js +8 -8
  66. package/dist/gulp/tasks/bundle.js +16 -16
  67. package/dist/gulp/tasks/defaults.js +3 -3
  68. package/dist/gulp/tasks/distribute.js +2 -2
  69. package/dist/gulp/tasks/html.js +9 -9
  70. package/dist/gulp/tasks/package-quick.js +3 -3
  71. package/dist/gulp/tasks/package.js +3 -3
  72. package/dist/gulp/tasks/release.js +3 -3
  73. package/dist/gulp/tasks/sass.js +6 -6
  74. package/dist/gulp/tasks/serve.js +4 -4
  75. package/dist/hooks/notarize-artifacts.js +1 -1
  76. package/dist/hooks/notarize.js +1 -1
  77. package/dist/index.js +5 -8
  78. package/dist/lib/_environment-mixin.js +50 -0
  79. package/dist/lib/_lifecycle-mixin.js +45 -0
  80. package/dist/lib/analytics.js +33 -35
  81. package/dist/lib/app-state.js +14 -14
  82. package/dist/lib/auth-flow.js +18 -18
  83. package/dist/lib/auth-persistence.js +12 -12
  84. package/dist/lib/auth.js +421 -0
  85. package/dist/lib/auto-updater.js +49 -49
  86. package/dist/lib/context-menu.js +13 -13
  87. package/dist/lib/context.js +19 -19
  88. package/dist/lib/deep-link.js +34 -34
  89. package/dist/lib/fontawesome.js +5 -5
  90. package/dist/lib/ipc.js +4 -4
  91. package/dist/lib/menu.js +25 -25
  92. package/dist/lib/protocol.js +5 -5
  93. package/dist/lib/remote-config.js +22 -22
  94. package/dist/lib/remote-scripts.js +21 -21
  95. package/dist/lib/restart-manager/index.js +28 -28
  96. package/dist/lib/sign-helpers/exec-with-limit.js +1 -1
  97. package/dist/lib/sign-helpers/sign-events.js +1 -1
  98. package/dist/lib/startup.js +18 -13
  99. package/dist/lib/storage.js +10 -10
  100. package/dist/lib/templating.js +16 -16
  101. package/dist/lib/theme.js +10 -10
  102. package/dist/lib/tray.js +27 -27
  103. package/dist/lib/usage.js +11 -11
  104. package/dist/lib/window-manager.js +26 -26
  105. package/dist/main.js +398 -483
  106. package/dist/preload.js +236 -176
  107. package/dist/renderer.js +417 -391
  108. package/dist/test/fixtures/consumer-app/config/omega.json5 +1 -1
  109. package/dist/test/fixtures/consumer-app/src/assets/js/components/main/index.js +8 -11
  110. package/dist/test/fixtures/consumer-app/src/main.js +5 -7
  111. package/dist/test/fixtures/consumer-app/src/preload.js +2 -2
  112. package/dist/test/harness/boot-entry.js +22 -20
  113. package/dist/test/harness/main-entry.js +31 -30
  114. package/dist/test/harness/renderer-entry.js +5 -5
  115. package/dist/test/harness/renderer-preload.js +137 -141
  116. package/dist/test/index.js +10 -10
  117. package/dist/test/runner.js +2 -2
  118. package/dist/test/runners/boot.js +7 -6
  119. package/dist/test/runners/electron.js +3 -2
  120. package/dist/test/runners/render-event.js +2 -2
  121. package/dist/test/suites/boot/consumer-app-boots.test.js +57 -26
  122. package/dist/test/suites/boot/restart-manager.test.js +2 -2
  123. package/dist/test/suites/boot/storage-bundled.test.js +5 -5
  124. package/dist/test/suites/boot/theme.test.js +13 -13
  125. package/dist/test/suites/build/audit.test.js +1 -1
  126. package/dist/test/suites/build/auth-persistence-resolve.test.js +6 -6
  127. package/dist/test/suites/build/boot-fixture.test.js +2 -2
  128. package/dist/test/suites/build/boot-runner-timeout.test.js +6 -5
  129. package/dist/test/suites/build/brand-scss.test.js +1 -1
  130. package/dist/test/suites/build/build-json-bake.test.js +1 -1
  131. package/dist/test/suites/build/cli.test.js +2 -2
  132. package/dist/test/suites/build/config-schema.test.js +5 -5
  133. package/dist/test/suites/build/defaults-scaffold.test.js +2 -2
  134. package/dist/test/suites/build/deploy-hook.test.js +3 -3
  135. package/dist/test/suites/build/ensure-target.test.js +2 -2
  136. package/dist/test/suites/build/env-delivery.test.js +2 -2
  137. package/dist/test/suites/build/esm-only-dependency.test.js +2 -2
  138. package/dist/test/suites/build/exports.test.js +9 -8
  139. package/dist/test/suites/build/get-config.test.js +4 -4
  140. package/dist/test/suites/build/manifest-deps.test.js +1 -1
  141. package/dist/test/suites/build/merge-line-files.test.js +1 -1
  142. package/dist/test/suites/build/omega-shell.test.js +34 -2
  143. package/dist/test/suites/build/omega.test.js +350 -0
  144. package/dist/test/suites/build/renderer-auth-bridge.test.js +211 -78
  145. package/dist/test/suites/build/runner.test.js +2 -2
  146. package/dist/test/suites/build/sentry.test.js +2 -2
  147. package/dist/test/suites/build/sign-windows-e2e.test.js +2 -2
  148. package/dist/test/suites/build/templating.test.js +3 -3
  149. package/dist/test/suites/build/test-stealth.test.js +7 -9
  150. package/dist/test/suites/build/url-helpers.test.js +55 -56
  151. package/dist/test/suites/build/validate-config.test.js +2 -2
  152. package/dist/test/suites/build/wave5-pins.test.js +2 -2
  153. package/dist/test/suites/main/analytics.test.js +59 -59
  154. package/dist/test/suites/main/app-state.test.js +66 -66
  155. package/dist/test/suites/main/auth-flow.test.js +41 -41
  156. package/dist/test/suites/main/auth-persistence.test.js +54 -43
  157. package/dist/test/suites/main/{client-bridge.integration.test.js → auth.integration.test.js} +10 -9
  158. package/dist/test/suites/main/auth.test.js +336 -0
  159. package/dist/test/suites/main/auto-updater.test.js +134 -134
  160. package/dist/test/suites/main/boot-sequence.test.js +37 -49
  161. package/dist/test/suites/main/context-menu.test.js +51 -50
  162. package/dist/test/suites/main/context.test.js +25 -25
  163. package/dist/test/suites/main/deep-link.test.js +74 -74
  164. package/dist/test/suites/main/fontawesome.test.js +27 -27
  165. package/dist/test/suites/main/ipc.test.js +35 -35
  166. package/dist/test/suites/main/menu.test.js +101 -100
  167. package/dist/test/suites/main/protocol.test.js +19 -19
  168. package/dist/test/suites/main/remote-config.test.js +63 -63
  169. package/dist/test/suites/main/remote-scripts.test.js +103 -103
  170. package/dist/test/suites/main/request.test.js +71 -0
  171. package/dist/test/suites/main/restart-manager.test.js +33 -33
  172. package/dist/test/suites/main/startup-paths-and-ua.test.js +4 -4
  173. package/dist/test/suites/main/startup.test.js +26 -26
  174. package/dist/test/suites/main/stealth-window.test.js +1 -1
  175. package/dist/test/suites/main/storage.test.js +25 -25
  176. package/dist/test/suites/main/theme.test.js +34 -34
  177. package/dist/test/suites/main/tray.test.js +79 -79
  178. package/dist/test/suites/main/url-helpers.test.js +133 -133
  179. package/dist/test/suites/main/usage.test.js +25 -25
  180. package/dist/test/suites/main/window-bounds.test.js +27 -27
  181. package/dist/test/suites/main/window-manager.test.js +44 -44
  182. package/dist/test/suites/renderer/analytics-bridge.test.js +5 -5
  183. package/dist/test/suites/renderer/cross-context-helpers.test.js +37 -31
  184. package/dist/test/suites/renderer/round-trip.test.js +3 -3
  185. package/dist/test/suites/renderer/tooltips.test.js +15 -15
  186. package/dist/test/suites/renderer/{window-em-surface.test.js → window-desktop-surface.test.js} +27 -7
  187. package/dist/test/utils/extended-mode-warning.js +1 -1
  188. package/dist/utils/boot-harness.js +56 -0
  189. package/dist/utils/mode-helpers.js +2 -15
  190. package/dist/utils/ship-keys.js +3 -3
  191. package/dist/utils/signing-status.js +51 -0
  192. package/dist/utils/test-events.js +7 -0
  193. package/dist/utils/test-stealth.js +6 -6
  194. package/dist/utils/url-helpers.js +52 -42
  195. package/dist/utils/user-agent.js +44 -0
  196. package/dist/vendor/account/engine.js +3 -3
  197. package/dist/vendor/account/index.js +14 -45
  198. package/dist/vendor/account/resolve-account.js +44 -0
  199. package/dist/vendor/account/schema.js +1 -1
  200. package/dist/vendor/account/user.js +99 -0
  201. package/dist/vendor/config/client-config.js +1 -1
  202. package/dist/vendor/config/environment.js +11 -30
  203. package/dist/vendor/config/index.js +8 -11
  204. package/dist/vendor/config/load.js +1 -2
  205. package/dist/vendor/config/platforms.js +1 -1
  206. package/dist/vendor/config/retired-keys.js +2 -2
  207. package/dist/vendor/config/schema.js +5 -8
  208. package/dist/vendor/config/site-global.js +2 -3
  209. package/dist/vendor/config/validate.js +1 -2
  210. package/dist/vendor/config/winback.js +1 -1
  211. package/dist/vendor/devkit/actions-secrets.js +1 -1
  212. package/dist/vendor/devkit/attach-log-file.js +1 -1
  213. package/dist/vendor/devkit/build-json.js +1 -1
  214. package/dist/vendor/devkit/cli-router.js +3 -4
  215. package/dist/vendor/devkit/defaults-engine.js +9 -11
  216. package/dist/vendor/devkit/local.js +2 -0
  217. package/dist/vendor/devkit/merge-line-files.js +2 -3
  218. package/dist/vendor/devkit/test/runner-core.js +6 -6
  219. package/dist/vendor/monitoring/env.js +2 -2
  220. package/dist/vendor/monitoring/index.js +1 -1
  221. package/dist/vendor/monitoring/main.js +1 -1
  222. package/dist/vendor/monitoring/preload.js +1 -1
  223. package/dist/vendor/monitoring/renderer.js +1 -1
  224. package/docs/analytics.md +8 -8
  225. package/docs/app-state.md +19 -19
  226. package/docs/audit.md +4 -4
  227. package/docs/{client-bridge.md → auth.md} +88 -73
  228. package/docs/auto-updater.md +8 -8
  229. package/docs/boot-sequence.md +11 -6
  230. package/docs/build-system.md +1 -1
  231. package/docs/cdp-debugging.md +1 -1
  232. package/docs/common-mistakes.md +7 -7
  233. package/docs/config-schema.md +1 -1
  234. package/docs/context-menu.md +13 -13
  235. package/docs/context.md +11 -11
  236. package/docs/css.md +3 -9
  237. package/docs/deep-link.md +25 -25
  238. package/docs/environment-detection.md +16 -16
  239. package/docs/fontawesome.md +7 -5
  240. package/docs/hooks.md +8 -8
  241. package/docs/index.md +38 -27
  242. package/docs/ipc.md +10 -10
  243. package/docs/lib-modules.md +9 -9
  244. package/docs/logging.md +12 -14
  245. package/docs/menu.md +18 -18
  246. package/docs/remote-config.md +9 -9
  247. package/docs/remote-scripts.md +12 -12
  248. package/docs/restart-manager.md +8 -8
  249. package/docs/sentry.md +4 -4
  250. package/docs/shared/analytics.md +1 -1
  251. package/docs/shared/breaking-changes.md +79 -13
  252. package/docs/shared/config.md +17 -21
  253. package/docs/shared/logging.md +1 -1
  254. package/docs/shared/monitoring.md +5 -5
  255. package/docs/shared/testing.md +2 -2
  256. package/docs/shared/theming.md +1 -1
  257. package/docs/shared/translation.md +19 -10
  258. package/docs/startup.md +16 -16
  259. package/docs/storage.md +11 -11
  260. package/docs/templating.md +3 -3
  261. package/docs/test-boot-layer.md +12 -12
  262. package/docs/test-framework.md +17 -17
  263. package/docs/themes.md +7 -7
  264. package/docs/tooltips.md +2 -2
  265. package/docs/tray.md +31 -31
  266. package/docs/usage.md +7 -7
  267. package/docs/verts.md +1 -1
  268. package/docs/windows.md +22 -22
  269. package/package.json +3 -4
  270. package/dist/lib/client-bridge.js +0 -374
  271. package/dist/lib/logger.js +0 -4
  272. package/dist/test/suites/build/manager.test.js +0 -213
  273. package/dist/test/suites/main/client-bridge.test.js +0 -262
@@ -39,8 +39,40 @@ module.exports = defineCases({
39
39
  ctx.expect(module.includes('data-shell-toggle')).toBe(true);
40
40
  ctx.expect(module.includes('data-shell-dismiss')).toBe(true);
41
41
  ctx.expect(module.includes("'shell.collapsed'")).toBe(true);
42
- // client is a runtime dependency, so the specifier survives vendoring.
43
- ctx.expect(module.includes("from '@omega.js/client'")).toBe(true);
42
+ // The shell is built FROM the runtime instance it is handed, so the
43
+ // vendored copy imports no runtime of its own.
44
+ ctx.expect(module.includes('export function createShell(omega)')).toBe(true);
45
+ ctx.expect(module.includes('@omega.js/client')).toBe(false);
46
+ },
47
+ },
48
+ {
49
+ // The renderer builds `omega.shell` from ITSELF, exactly as web's runtime
50
+ // does (`this.shell = createShell(this)`), off the vendored module
51
+ name: 'the renderer builds omega.shell with createShell(omega)',
52
+ run: (ctx) => {
53
+ const renderer = fs.readFileSync(path.join(PACKAGE_ROOT, 'dist', 'renderer.js'), 'utf8');
54
+ ctx.expect(renderer.includes("const { createShell } = require('./assets/js/core/app-shell.js');")).toBe(true);
55
+ ctx.expect(renderer.includes('this.shell = createShell(this);')).toBe(true);
56
+ },
57
+ },
58
+ {
59
+ // The same function object the renderer calls, and it builds the shell API
60
+ // off the instance's storage (an inert API when the page carries no shell)
61
+ name: 'createShell(omega) returns the shell API off the instance it is handed',
62
+ run: (ctx) => {
63
+ const { createShell } = require(path.join(PACKAGE_ROOT, 'dist', 'assets', 'js', 'core', 'app-shell.js'));
64
+ const savedDocument = globalThis.document;
65
+ globalThis.document = { querySelector: () => null };
66
+ try {
67
+ const shell = createShell({ storage: { get: () => null, set: () => {} } });
68
+ for (const name of ['isCollapsed', 'isOpen', 'setCollapsed', 'setOpen', 'toggleCollapsed', 'toggleOpen']) {
69
+ ctx.expect(typeof shell[name]).toBe('function');
70
+ }
71
+ ctx.expect(shell.isCollapsed()).toBe(false);
72
+ } finally {
73
+ if (savedDocument === undefined) delete globalThis.document;
74
+ else globalThis.document = savedDocument;
75
+ }
44
76
  },
45
77
  },
46
78
  {
@@ -0,0 +1,350 @@
1
+ // Build-layer tests for the ONE `omega` runtime each Electron process exports
2
+ // ([#945](https://github.com/Omega-JS-Stack/omega/issues/945)), and for the
3
+ // build-time module (build.js) beside them.
4
+ //
5
+ // main.js, preload.js and renderer.js each export ONE ready-made instance as the
6
+ // module and its class as `.Omega`; a consumer never writes `new`. The renderer
7
+ // extends @omega.js/client's base class and requires the preload's bridge, so it
8
+ // is loaded here with a `window.desktop` present (and pinned to refuse to load
9
+ // without one). Everything that needs a real Electron is the main layer's.
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const build = require('../../../build.js');
14
+ const defineCases = require('../../../vendor/devkit/test/define-cases.js');
15
+
16
+ const ROOT = path.join(__dirname, '..', '..', '..');
17
+ const read = (file) => fs.readFileSync(path.join(ROOT, file), 'utf8');
18
+
19
+ /**
20
+ * Load renderer.js fresh with `window` set to `win` (null = no window at all),
21
+ * then put the globals back.
22
+ * @param {object|null} win - the window the module loads under.
23
+ * @returns {object} the module's export.
24
+ */
25
+ function loadRenderer(win) {
26
+ const file = require.resolve(path.join(ROOT, 'renderer.js'));
27
+ const saved = globalThis.window;
28
+ delete require.cache[file];
29
+ if (win) globalThis.window = win;
30
+ else delete globalThis.window;
31
+ try {
32
+ return require(file);
33
+ } finally {
34
+ delete require.cache[file];
35
+ if (saved === undefined) delete globalThis.window;
36
+ else globalThis.window = saved;
37
+ }
38
+ }
39
+
40
+ // The production preload's `window.desktop` keys, in source order
41
+ const DESKTOP_KEYS = ['environment', 'ipc', 'storage', 'theme', 'fontawesome', 'logger', 'autoUpdater', 'analytics', 'context', 'usage', 'remoteConfig'];
42
+
43
+ // The one input and the two lane flags that decide it, saved and restored
44
+ // around every case that touches them (#817).
45
+ const LANE_KEYS = ['OMEGA_ENVIRONMENT', 'OMEGA_BUILD_MODE', 'OMEGA_TEST_MODE', 'NODE_ENV'];
46
+
47
+ /**
48
+ * Run `fn` with exactly `vars` set on the lane keys (null clears them all).
49
+ * @param {object|null} vars - the lane env for this case.
50
+ * @param {function} fn - the body.
51
+ * @returns {*} whatever `fn` returns.
52
+ */
53
+ function withEnvironment(vars, fn) {
54
+ const saved = {};
55
+ for (const key of LANE_KEYS) saved[key] = process.env[key];
56
+ try {
57
+ for (const key of LANE_KEYS) delete process.env[key];
58
+ Object.assign(process.env, vars || {});
59
+ return fn();
60
+ } finally {
61
+ for (const key of LANE_KEYS) {
62
+ if (saved[key] === undefined) delete process.env[key];
63
+ else process.env[key] = saved[key];
64
+ }
65
+ }
66
+ }
67
+
68
+ /**
69
+ * What src/build.js resolves at LOAD for a given lane. build.js sets the input
70
+ * once, at require time, so this loads a fresh copy of it per lane.
71
+ * @param {object} vars - the lane env.
72
+ * @returns {string} the resolved environment.
73
+ */
74
+ function laneEnvironment(vars) {
75
+ const buildPath = require.resolve('../../../build.js');
76
+ return withEnvironment(vars, () => {
77
+ const saved = require.cache[buildPath];
78
+ delete require.cache[buildPath];
79
+ try {
80
+ return require(buildPath).getEnvironment();
81
+ } finally {
82
+ if (saved) require.cache[buildPath] = saved;
83
+ else delete require.cache[buildPath];
84
+ }
85
+ });
86
+ }
87
+
88
+ module.exports = defineCases({
89
+ type: 'group', // independent tests; run all even on failure
90
+ layer: 'build',
91
+ description: 'Omega runtimes (main, preload, renderer) + the build module (build.js)',
92
+ tests: [
93
+ {
94
+ name: 'main and preload export ONE instance each, and .Omega is its constructor',
95
+ run: (ctx) => {
96
+ for (const file of ['main.js', 'preload.js']) {
97
+ const omega = require(path.join(ROOT, file));
98
+ ctx.expect(typeof omega.Omega).toBe('function');
99
+ ctx.expect(omega).toBeInstanceOf(omega.Omega);
100
+ ctx.expect(omega.constructor).toBe(omega.Omega);
101
+ ctx.expect(typeof omega.initialize).toBe('function');
102
+ ctx.expect(omega.ready).toBeInstanceOf(Promise);
103
+ }
104
+ },
105
+ },
106
+ {
107
+ name: 'main carries every library as a plain property, `auth` among them and no `omega`',
108
+ run: (ctx) => {
109
+ const omega = require(path.join(ROOT, 'main.js'));
110
+ ctx.expect(omega.auth).toBe(require(path.join(ROOT, 'lib', 'auth.js')));
111
+ ctx.expect(omega.omega).toBeUndefined();
112
+ for (const name of ['getEnvironment', 'isDevelopment', 'isProduction', 'isTesting', 'getVersion', 'getFunctionsUrl', 'getApiUrl', 'getWebsiteUrl', 'getAuthUrl', 'openAuthFlow', 'quit', 'relaunch', 'require']) {
113
+ ctx.expect(typeof omega[name]).toBe('function');
114
+ }
115
+ ctx.expect(typeof omega.Omega.require).toBe('function');
116
+ },
117
+ },
118
+ {
119
+ name: 'preload initialize() outside a BrowserWindow settles ready with the instance',
120
+ run: async (ctx) => {
121
+ const { Omega } = require(path.join(ROOT, 'preload.js'));
122
+ const preload = new Omega();
123
+ ctx.expect(await preload.initialize()).toBe(preload);
124
+ ctx.expect(await preload.ready).toBe(preload);
125
+ },
126
+ },
127
+ {
128
+ // A window built without the framework's preload has no bridge: a
129
+ // programmer error, loud at load
130
+ name: 'renderer refuses to load without window.desktop',
131
+ run: (ctx) => {
132
+ ctx.expect(() => loadRenderer(null)).toThrow(/window\.desktop is missing/);
133
+ ctx.expect(() => loadRenderer({})).toThrow(/window\.desktop is missing/);
134
+ },
135
+ },
136
+ {
137
+ name: 'renderer exports ONE instance of a subclass of the client base, with omega.desktop the bridge',
138
+ run: async (ctx) => {
139
+ const { Omega: ClientOmega } = require('@omega.js/client');
140
+ const desktop = { ipc: {}, storage: {} };
141
+ const omega = loadRenderer({ desktop });
142
+
143
+ ctx.expect(typeof omega.Omega).toBe('function');
144
+ ctx.expect(omega).toBeInstanceOf(omega.Omega);
145
+ ctx.expect(omega).toBeInstanceOf(ClientOmega);
146
+ ctx.expect(omega.desktop).toBe(desktop);
147
+ ctx.expect(omega.storage === desktop.storage).toBe(false);
148
+ ctx.expect(omega.auth.user.constructor.name).toBe('User');
149
+ ctx.expect(omega.auth.user.authenticated).toBe(false);
150
+ for (const name of ['signOut', 'getMainUser', 'enableFontAwesome', 'getWebsiteUrl', 'getAuthUrl', 'getVersion']) {
151
+ ctx.expect(typeof omega[name]).toBe('function');
152
+ }
153
+ },
154
+ },
155
+ {
156
+ name: 'each process module defines class Omega and exports its instance (source pin)',
157
+ run: (ctx) => {
158
+ for (const file of ['main.js', 'preload.js', 'renderer.js']) {
159
+ const source = read(file);
160
+ ctx.expect(source).toMatch(/^const omega = new Omega\(\);$/m);
161
+ ctx.expect(source).toMatch(/^module\.exports = omega;$/m);
162
+ ctx.expect(source).toMatch(/^module\.exports\.Omega = Omega;$/m);
163
+ ctx.expect(source.includes('attachTo')).toBe(false);
164
+ ctx.expect(source.includes('build.prototype')).toBe(false);
165
+ }
166
+ ctx.expect(read('main.js')).toMatch(/^class Omega \{$/m);
167
+ ctx.expect(read('preload.js')).toMatch(/^class Omega \{$/m);
168
+ ctx.expect(read('renderer.js')).toMatch(/^class Omega extends ClientOmega \{$/m);
169
+ ctx.expect(read('renderer.js').includes('this.shell = createShell(this);')).toBe(true);
170
+ ctx.expect(read('main.js').includes('wmBridge')).toBe(false);
171
+ },
172
+ },
173
+ {
174
+ // The preload global keeps its name and its shape
175
+ name: 'the production preload exposes window.desktop with the same namespaces (source pin)',
176
+ run: (ctx) => {
177
+ const source = read('preload.js');
178
+ const start = source.indexOf("contextBridge.exposeInMainWorld('desktop', {");
179
+ const block = source.slice(start, source.indexOf(' });\n', start));
180
+ const keys = [...block.matchAll(/^ ([A-Za-z]+): /gm)].map((match) => match[1]);
181
+ ctx.expect(keys).toEqual(DESKTOP_KEYS);
182
+ },
183
+ },
184
+ {
185
+ // `.` is the build-time entry; each process imports its instance by subpath
186
+ name: 'the package root exports { version, build } and nothing else',
187
+ run: (ctx) => {
188
+ const root = require(path.join(ROOT, 'index.js'));
189
+ ctx.expect(Object.keys(root).sort()).toEqual(['build', 'version']);
190
+ ctx.expect(root.build).toBe(build);
191
+ },
192
+ },
193
+ {
194
+ name: 'the build module is one plain object: no class, no new',
195
+ run: (ctx) => {
196
+ ctx.expect(typeof build).toBe('object');
197
+ ctx.expect(typeof build.getConfig).toBe('function');
198
+ ctx.expect(read('build.js')).toMatch(/^module\.exports = \{$/m);
199
+ },
200
+ },
201
+ {
202
+ name: 'getMode returns the mode shape',
203
+ run: (ctx) => {
204
+ const mode = build.getMode();
205
+ ctx.expect(mode).toHaveProperty('build');
206
+ ctx.expect(mode).toHaveProperty('publish');
207
+ ctx.expect(mode).toHaveProperty('server');
208
+ ctx.expect(mode).toHaveProperty('environment');
209
+ ctx.expect(['development', 'testing', 'production']).toContain(mode.environment);
210
+ },
211
+ },
212
+ {
213
+ // The environment reads ONE input, `OMEGA_ENVIRONMENT`
214
+ // ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)), and the
215
+ // lane that boots or builds this app sets it (src/build.js does, at load).
216
+ // Nothing sniffs NODE_ENV, app.isPackaged or OMEGA_TEST_MODE any more.
217
+ name: 'getEnvironment answers the one input, for each of the three names',
218
+ run: (ctx) => {
219
+ withEnvironment(null, () => {
220
+ for (const name of ['development', 'testing', 'production']) {
221
+ process.env.OMEGA_ENVIRONMENT = name;
222
+ ctx.expect(build.getEnvironment()).toBe(name);
223
+ }
224
+ });
225
+ },
226
+ },
227
+ {
228
+ // The bug this replaced: with no signal desktop's own copy answered
229
+ // 'production', so a plain `npm start` bundled itself as a production
230
+ // artifact, while @omega.js/extension's copy of the same function
231
+ // answered 'development' from the same inputs (#817).
232
+ name: 'the build lane resolves production, a dev boot resolves development',
233
+ run: (ctx) => {
234
+ const buildLane = laneEnvironment({ OMEGA_BUILD_MODE: 'true' });
235
+ ctx.expect(buildLane).toBe('production');
236
+
237
+ const devBoot = laneEnvironment({});
238
+ ctx.expect(devBoot).toBe('development');
239
+
240
+ // A lane that already named one keeps it, EXCEPT a build lane: a
241
+ // production build spawned from a test run still bakes production.
242
+ ctx.expect(laneEnvironment({ OMEGA_ENVIRONMENT: 'testing' })).toBe('testing');
243
+ ctx.expect(laneEnvironment({ OMEGA_ENVIRONMENT: 'testing', OMEGA_BUILD_MODE: 'true' })).toBe('production');
244
+ },
245
+ },
246
+ {
247
+ name: 'no input at all is a loud error naming OMEGA_ENVIRONMENT, never a default',
248
+ run: (ctx) => {
249
+ withEnvironment(null, () => {
250
+ delete process.env.OMEGA_ENVIRONMENT;
251
+ ctx.expect(() => build.getEnvironment()).toThrow(/OMEGA_ENVIRONMENT/);
252
+ process.env.OMEGA_ENVIRONMENT = 'staging';
253
+ ctx.expect(() => build.getEnvironment()).toThrow(/OMEGA_ENVIRONMENT/);
254
+ });
255
+ },
256
+ },
257
+ {
258
+ // The core invariant: is*() DERIVE from getEnvironment(), so they can
259
+ // NEVER disagree with it, and exactly one is always true.
260
+ name: 'invariant: is*() exactly matches getEnvironment() + mutually exclusive (every scenario)',
261
+ run: (ctx) => {
262
+ withEnvironment(null, () => {
263
+ for (const name of ['development', 'testing', 'production']) {
264
+ process.env.OMEGA_ENVIRONMENT = name;
265
+ const e = build.getEnvironment();
266
+ ctx.expect(e).toBe(name);
267
+ ctx.expect(build.isDevelopment()).toBe(e === 'development');
268
+ ctx.expect(build.isTesting()).toBe(e === 'testing');
269
+ ctx.expect(build.isProduction()).toBe(e === 'production');
270
+ const trueCount = [build.isDevelopment(), build.isTesting(), build.isProduction()].filter(Boolean).length;
271
+ ctx.expect(trueCount).toBe(1);
272
+ }
273
+ });
274
+ },
275
+ },
276
+ {
277
+ name: 'getPackage("main") resolves to @omega.js/desktop package.json',
278
+ run: (ctx) => {
279
+ const pkg = build.getPackage('main');
280
+ ctx.expect(pkg.name).toBe('@omega.js/desktop');
281
+ ctx.expect(pkg).toHaveProperty('version');
282
+ ctx.expect(pkg).toHaveProperty('exports');
283
+ },
284
+ },
285
+ {
286
+ name: 'getRootPath("main") returns a non-empty string',
287
+ run: (ctx) => {
288
+ const root = build.getRootPath('main');
289
+ ctx.expect(typeof root).toBe('string');
290
+ ctx.expect(root.length).toBeGreaterThan(0);
291
+ },
292
+ },
293
+ {
294
+ name: 'getLiveReloadPort defaults to 35729',
295
+ run: (ctx) => {
296
+ const prev = process.env.OMEGA_LIVERELOAD_PORT;
297
+ delete process.env.OMEGA_LIVERELOAD_PORT;
298
+ try {
299
+ ctx.expect(build.getLiveReloadPort()).toBe(35729);
300
+ } finally {
301
+ if (prev !== undefined) process.env.OMEGA_LIVERELOAD_PORT = prev;
302
+ }
303
+ },
304
+ },
305
+ {
306
+ name: 'getWindowsSignStrategy defaults to self-hosted when no config',
307
+ run: (ctx) => {
308
+ // Config is the only source of the strategy: no env var sets it.
309
+ // Run from a cwd with no omega.json5 to confirm the default.
310
+ const fs = require('fs'); const os = require('os'); const path = require('path');
311
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-strategy-'));
312
+ const orig = process.cwd();
313
+ try {
314
+ process.chdir(tmp);
315
+ ctx.expect(build.getWindowsSignStrategy()).toBe('self-hosted');
316
+ } finally {
317
+ process.chdir(orig);
318
+ fs.rmSync(tmp, { recursive: true, force: true });
319
+ }
320
+ },
321
+ },
322
+ {
323
+ name: 'getWindowsSignStrategy reads config platforms.windows.signing.strategy',
324
+ run: (ctx) => {
325
+ const fs = require('fs'); const os = require('os'); const path = require('path');
326
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-strategy-'));
327
+ fs.mkdirSync(path.join(tmp, 'config'), { recursive: true });
328
+ fs.writeFileSync(path.join(tmp, 'config', 'omega.json5'),
329
+ `{ targets: { desktop: { type: 'desktop', platforms: { windows: { signing: { strategy: 'cloud' } } } } } }`);
330
+ const orig = process.cwd();
331
+ try {
332
+ process.chdir(tmp);
333
+ ctx.expect(build.getWindowsSignStrategy()).toBe('cloud');
334
+ } finally {
335
+ process.chdir(orig);
336
+ fs.rmSync(tmp, { recursive: true, force: true });
337
+ }
338
+ },
339
+ },
340
+ {
341
+ name: 'logger returns a named logger',
342
+ run: (ctx) => {
343
+ const logger = build.logger('test-name');
344
+ ctx.expect(logger.name).toBe('test-name');
345
+ ctx.expect(typeof logger.log).toBe('function');
346
+ ctx.expect(typeof logger.error).toBe('function');
347
+ },
348
+ },
349
+ ],
350
+ });