diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 84b590eda4..ca0ae43cfc 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -47,7 +47,11 @@ jobs:
run: pnpm lint:hbs
- name: Lint (js)
run: pnpm lint:js
- - name: Run test
+ - name: build
+ run: EMBER_ENV=test pnpm ember build --environment test
+ - name: test ember debug
+ run: pnpm ember-debug:test
+ - name: Run test inspector ui
run: pnpm test
env:
COVERAGE: 'true'
@@ -110,14 +114,12 @@ jobs:
- name: Set NO_EXTEND_PROTOTYPES
if: matrix.scenario == 'ember-default-no-prototype-extensions'
run: echo "NO_EXTEND_PROTOTYPES==true" >> .GITHUB_ENV
- - name: Setup ember-try scenario
- run: pnpm ember try:one ${{ matrix.scenario }} --skip-cleanup --- cat package.json
- - name: Build
+ - name: Build Inspector
run: pnpm ember build --environment test
+ - name: Setup ember-try scenario
+ run: pnpm ember-debug:try:one ${{ matrix.scenario }} --skip-cleanup --- cat package.json
- name: Run test
- # Due to a bug in ember-cli, running `ember test` with `--path` doesn't set `EMBER_ENV=test`
- # See https://github.com/ember-cli/ember-cli/issues/8922
- run: EMBER_ENV=test pnpm ember test --path dist --filter="Ember Debug"
+ run: pnpm ember-debug:test
build:
name: Build extensions
diff --git a/.gitignore b/.gitignore
index 741b8e7b8d..4241b06d61 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,8 @@
# dependencies
/node_modules/
+/test-apps/classic/dist
+/test-apps/classic/node_modules
# misc
/.env*
diff --git a/ember_debug/rollup.config.js b/ember_debug/rollup.config.js
index a681c7962c..b7799a8bd0 100644
--- a/ember_debug/rollup.config.js
+++ b/ember_debug/rollup.config.js
@@ -11,6 +11,7 @@ export default {
'utils/type-check.js',
'port.js',
'utils/ember.js',
+ 'utils/type-check',
'models/profile-node.js',
'libs/promise-assembler.js',
'lib/versions.js',
@@ -20,5 +21,11 @@ export default {
dir: 'dist',
},
- plugins: [babel(), nodeResolve(), commonjs(), del({ targets: 'dist' })],
+ plugins: [
+ babel(),
+ nodeResolve(),
+ commonjs(),
+ // eslint-disable-next-line no-undef
+ process.env.NO_DEL_DIST && del({ targets: 'dist' }),
+ ].filter(Boolean),
};
diff --git a/ember_debug/utils/version.js b/ember_debug/utils/version.js
index d07b125267..12a6030d37 100644
--- a/ember_debug/utils/version.js
+++ b/ember_debug/utils/version.js
@@ -34,6 +34,8 @@ export function isInVersionSpecifier(specifier, version) {
let operator = specifier[0];
if (Number.isNaN(+operator)) {
specifier = specifier.slice(1);
+ } else {
+ return specifier === version;
}
specifier = cleanupVersion(specifier).split('.');
version2 = cleanupVersion(version).split('.');
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 5aed6b609e..8546720f338 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -62,6 +62,10 @@ export default ts.config(
'dist/',
'ember_debug/dist/',
'node_modules/',
+ 'test-apps/classic/node_modules/',
+ 'test-apps/classic/dist/',
+ 'test-apps/classic/public/',
+ 'test-apps/tests/helpers/index.ts',
'coverage/',
'!**/.*',
'vendor/',
@@ -93,6 +97,7 @@ export default ts.config(
...globals.browser,
basicContext: false,
requireModule: false,
+ chrome: true,
},
},
},
@@ -113,10 +118,21 @@ export default ts.config(
},
},
{
- files: ['tests/**/*-test.{js,gjs,ts,gts}'],
+ files: [
+ 'tests/**/*-test.{js,gjs,ts,gts}',
+ 'test-apps/classic/tests/**/*-test.{js,gjs,ts,gts}',
+ ],
plugins: {
qunit,
},
+ languageOptions: {
+ globals: {
+ ...globals.browser,
+ basicContext: false,
+ requireModule: false,
+ chrome: true,
+ },
+ },
},
/**
* CJS node files
@@ -125,15 +141,18 @@ export default ts.config(
files: [
'**/*.cjs',
'config/**/*.js',
+ 'test-apps/classic/config/**/*.js',
'lib/*/index.js',
'scripts/**/*.js',
'testem.js',
+ 'test-apps/classic/testem.js',
'testem*.js',
'.prettierrc.js',
'.stylelintrc.js',
'.template-lintrc.js',
'babel.config.js',
'ember-cli-build.js',
+ 'test-apps/classic/ember-cli-build.js',
'gulpfile.js',
],
plugins: {
diff --git a/package.json b/package.json
index 5f3fa8458c..a8e2ca987e 100644
--- a/package.json
+++ b/package.json
@@ -30,12 +30,14 @@
"start": "ember serve",
"test": "concurrently \"pnpm:lint\" \"pnpm:test:*\" --names \"lint,test:\" --prefixColors auto",
"test:ember": "pnpm build:ember-debug && COVERAGE=true ember test",
- "watch": "pnpm '/watch:/'",
"watch-test": "pnpm '/watch-test:/'",
"watch-test:ember-debug": "pnpm --filter ember-debug watch",
"watch-test:inspector-ui": "ember test --serv",
+ "watch": "export DEL_RUN_ONCE=true; pnpm build:ember-debug && pnpm '/watch:/'",
+ "watch:inspector-ui": "ember build --watch",
"watch:ember-debug": "pnpm --filter ember-debug watch",
- "watch:inspector-ui": "ember build --watch"
+ "ember-debug:try:one": "pnpm --filter '*' ember:try:one",
+ "ember-debug:test": "pnpm --filter '*' ember-debug-test"
},
"dependencies": {
"got": "^11.8.6",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3fe181a692..888e96730e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -396,6 +396,129 @@ importers:
specifier: ^1.2.1
version: 1.2.1
+ test-apps/classic:
+ devDependencies:
+ '@babel/core':
+ specifier: ^7.26.0
+ version: 7.26.0
+ '@babel/eslint-parser':
+ specifier: ^7.25.9
+ version: 7.26.5(@babel/core@7.26.0)(eslint@9.18.0)
+ '@babel/plugin-proposal-decorators':
+ specifier: ^7.25.9
+ version: 7.25.9(@babel/core@7.26.0)
+ '@ember/optional-features':
+ specifier: ^2.2.0
+ version: 2.2.0
+ '@ember/render-modifiers':
+ specifier: ^3.0.0
+ version: 3.0.0(@glint/template@1.5.1)(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1))
+ '@ember/string':
+ specifier: ^4.0.0
+ version: 4.0.0
+ '@ember/test-helpers':
+ specifier: ^4.0.4
+ version: 4.0.4(@babel/core@7.26.0)(@glint/template@1.5.1)(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1))
+ '@eslint/js':
+ specifier: ^9.17.0
+ version: 9.18.0
+ '@glimmer/component':
+ specifier: ^1.1.2
+ version: 1.1.2(@babel/core@7.26.0)
+ '@glimmer/tracking':
+ specifier: ^1.1.2
+ version: 1.1.2
+ broccoli-asset-rev:
+ specifier: ^3.0.0
+ version: 3.0.0
+ concurrently:
+ specifier: ^9.1.0
+ version: 9.1.2
+ ember-auto-import:
+ specifier: ^2.10.0
+ version: 2.10.0(@glint/template@1.5.1)(webpack@5.97.1)
+ ember-cli:
+ specifier: ~6.1.0
+ version: 6.1.0(handlebars@4.7.8)(underscore@1.13.7)
+ ember-cli-babel:
+ specifier: ^8.2.0
+ version: 8.2.0(@babel/core@7.26.0)
+ ember-cli-clean-css:
+ specifier: ^3.0.0
+ version: 3.0.0
+ ember-cli-dependency-checker:
+ specifier: ^3.3.3
+ version: 3.3.3(ember-cli@6.1.0(handlebars@4.7.8)(underscore@1.13.7))
+ ember-cli-htmlbars:
+ specifier: ^6.3.0
+ version: 6.3.0
+ ember-cli-inject-live-reload:
+ specifier: ^2.1.0
+ version: 2.1.0(patch_hash=enhtbujp77hfcye7o4pfeqcdua)
+ ember-cli-sri:
+ specifier: ^2.1.1
+ version: 2.1.1
+ ember-cli-terser:
+ specifier: ^4.0.2
+ version: 4.0.2
+ ember-debug:
+ specifier: workspace:*
+ version: link:../../ember_debug
+ ember-fetch:
+ specifier: ^8.1.2
+ version: 8.1.2(encoding@0.1.13)
+ ember-in-element-polyfill:
+ specifier: ^1.0.1
+ version: 1.0.1
+ ember-load-initializers:
+ specifier: ^3.0.1
+ version: 3.0.1(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1))
+ ember-modifier:
+ specifier: ^4.2.0
+ version: 4.2.0(@babel/core@7.26.0)(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1))
+ ember-page-title:
+ specifier: ^8.2.3
+ version: 8.2.4(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1))
+ ember-qunit:
+ specifier: ^8.1.1
+ version: 8.1.1(@ember/test-helpers@4.0.4(@babel/core@7.26.0)(@glint/template@1.5.1)(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1)))(@glint/template@1.5.1)(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1))(qunit@2.24.1)
+ ember-resolver:
+ specifier: ^13.1.0
+ version: 13.1.0(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1))
+ ember-sinon-qunit:
+ specifier: ^7.5.0
+ version: 7.5.0(@babel/core@7.26.0)(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1))(qunit@2.24.1)(sinon@15.2.0)
+ ember-source:
+ specifier: ^5.0.0
+ version: 5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1)
+ ember-template-lint:
+ specifier: ^6.0.0
+ version: 6.0.0
+ ember-try:
+ specifier: ^3.0.0
+ version: 3.0.0(encoding@0.1.13)
+ ember-welcome-page:
+ specifier: ^7.0.2
+ version: 7.0.2
+ ember-wormhole:
+ specifier: ^0.6.0
+ version: 0.6.0
+ loader.js:
+ specifier: ^4.7.0
+ version: 4.7.0
+ qunit:
+ specifier: ^2.24.1
+ version: 2.24.1
+ qunit-dom:
+ specifier: ^3.4.0
+ version: 3.4.0
+ tracked-built-ins:
+ specifier: ^3.4.0
+ version: 3.4.0(@babel/core@7.26.0)
+ webpack:
+ specifier: ^5.97.1
+ version: 5.97.1
+
packages:
'@ampproject/remapping@2.3.0':
@@ -1220,6 +1343,16 @@ packages:
'@glint/template':
optional: true
+ '@ember/render-modifiers@3.0.0':
+ resolution: {integrity: sha512-gJztS8dI7Jt8ohFQptEDJAgpl9DG84IpqwQoR1JDpVIBy2uLbf8KFD6S3h3LfyMsgJce6G38cOvyQv6BDgcnsA==}
+ engines: {node: '>= 18'}
+ peerDependencies:
+ '@glint/template': ^1.0.2
+ ember-source: '>= 4.0.0'
+ peerDependenciesMeta:
+ '@glint/template':
+ optional: true
+
'@ember/string@3.1.1':
resolution: {integrity: sha512-UbXJ+k3QOrYN4SRPHgXCqYIJ+yWWUg1+vr0H4DhdQPTy8LJfyqwZ2tc5uqpSSnEXE+/1KopHBE5J8GDagAg5cg==}
engines: {node: 12.* || 14.* || >= 16}
@@ -2878,6 +3011,9 @@ packages:
resolution: {integrity: sha512-YoUHeKnPi4xIGZ2XDVN9oHNA9k3xF5f5vlA+1wvrxIIDXqQU97gp2FxVAF503Zxdtt0C5CRB5n+47k2hlkaBzA==}
engines: {node: '>= 0.10.0'}
+ broccoli-caching-writer@2.3.1:
+ resolution: {integrity: sha512-lfoDx98VaU8tG4mUXCxKdKyw2Lr+iSIGUjCgV83KC2zRC07SzYTGuSsMqpXFiOQlOGuoJxG3NRoyniBa1BWOqA==}
+
broccoli-caching-writer@3.0.3:
resolution: {integrity: sha512-g644Kb5uBPsy+6e2DvO3sOc+/cXZQQNgQt64QQzjA9TSdP0dl5qvetpoNIx4sy/XIjrPYG1smEidq9Z9r61INw==}
@@ -2915,6 +3051,9 @@ packages:
resolution: {integrity: sha512-ng4eIhPYiXqMw6SyGoxPHR3YAwEd2lr9FgBI1CyTbspl4txZovOsmzFkMkGAlu88xyvYXJqHiM2crfLa65T1BQ==}
engines: {node: 10.* || >= 12.*}
+ broccoli-kitchen-sink-helpers@0.2.9:
+ resolution: {integrity: sha512-C+oEqivDofZv/h80rgN4WJkbZkbfwkrIeu8vFn4bb4m4jPd3ICNNplhkXGl3ps439pzc2yjZ1qIwz0yy8uHcQg==}
+
broccoli-kitchen-sink-helpers@0.3.1:
resolution: {integrity: sha512-gqYnKSJxBSjj/uJqeuRAzYVbmjWhG0mOZ8jrp6+fnUIOgLN6MvI7XxBECDHkYMIFPJ8Smf4xaI066Q2FqQDnXg==}
@@ -2959,6 +3098,9 @@ packages:
resolution: {integrity: sha512-Q+8iezprZzL9voaBsDY3rQVl7c7H5h+bvv8SpzCZXPZgfBFCbx7KFQ2c3rZR6lW5k4Kwoqt7jG+rZMUg67Gwxw==}
engines: {node: 10.* || >= 12.*}
+ broccoli-plugin@1.1.0:
+ resolution: {integrity: sha512-dY1QsA20of9wWEto8yhN7JQjpfjySmgeIMsvnQ9aBAv1wEJJCe04B0ekdgq7Bduyx9yWXdoC5CngGy81swmp2w==}
+
broccoli-plugin@1.3.1:
resolution: {integrity: sha512-DW8XASZkmorp+q7J4EeDEZz+LoyKLAd2XZULXyD9l4m9/hAKV3vjHmB1kiUshcWAYMgTP1m2i4NnqCE/23h6AQ==}
@@ -2996,6 +3138,9 @@ packages:
resolution: {integrity: sha512-ZbGVQjivWi0k220fEeIUioN6Y68xjMy0xiLAc0LdieHI99gw+tafU8w0CggBDYVNsJMKUr006AZaM7gNEwCxEg==}
engines: {node: 8.* || 10.* || >= 12.*}
+ broccoli-sri-hash@2.1.2:
+ resolution: {integrity: sha512-toLD/v7ut2ajcH8JsdCMG2Bpq2qkwTcKM6CMzVMSAJjaz/KpK69fR+gSqe1dsjh+QTdxG0yVvkq3Sij/XMzV6A==}
+
broccoli-stew@3.0.0:
resolution: {integrity: sha512-NXfi+Vas24n3Ivo21GvENTI55qxKu7OwKRnCLWXld8MiLiQKQlWIq28eoARaFj0lTUFwUa4jKZeA7fW9PiWQeg==}
engines: {node: 8.* || >= 10.*}
@@ -4153,6 +4298,10 @@ packages:
resolution: {integrity: sha512-RMlFPMK4kaB+67seF/IIoY3EC4rRd+L58q+lyElrxB3FcQTgph/qmGwtqf9Up7m3SDbPiA7cccCOSmgReMgCXA==}
engines: {node: '>= 10.*'}
+ ember-cli-sri@2.1.1:
+ resolution: {integrity: sha512-YG/lojDxkur9Bnskt7xB6gUOtJ6aPl/+JyGYm9HNDk3GECVHB3SMN3rlGhDKHa1ndS5NK2W2TSLb9bzRbGlMdg==}
+ engines: {node: '>= 0.10.0'}
+
ember-cli-string-utils@1.1.0:
resolution: {integrity: sha512-PlJt4fUDyBrC/0X+4cOpaGCiMawaaB//qD85AXmDRikxhxVzfVdpuoec02HSiTGTTB85qCIzWBIh8lDOiMyyFg==}
@@ -4277,6 +4426,12 @@ packages:
resolution: {integrity: sha512-Pz7muUcwzgAVGQ3ZNCdY/KMKtmvtJk5DWetuvx2MVHZCRpVzSRvkVa2tKXcp4tmz/COYUysneJxAR4tmwAyH9Q==}
engines: {node: 12.* || 14.* || >= 16}
+ ember-page-title@8.2.4:
+ resolution: {integrity: sha512-ZZ912IRItIEfD5+35w65DT9TmqppK+suXJeaJenD5OSuvujUnYl6KxBpyAbfjw4mYtURwJO/TmSe+4GGJbsJ0w==}
+ engines: {node: 16.* || >= 18}
+ peerDependencies:
+ ember-source: '>= 3.28.0'
+
ember-qunit@8.1.1:
resolution: {integrity: sha512-nT+6s74j3BKNn+QQY/hINC3Xw3kn0NF0cU9zlgVQmCBWoyis1J24xWrY2LFOMThPmF6lHqcrUb5JwvBD4BXEXg==}
peerDependencies:
@@ -4378,6 +4533,10 @@ packages:
resolution: {integrity: sha512-ZYVKYWMnrHSD3vywo7rV76kPCOC9ATIEnGGG/PEKfCcFE0lB26jltRDnOrhORfLKq0JFp62fFxC/4940U+MwRQ==}
engines: {node: 16.* || >= 18.*}
+ ember-welcome-page@7.0.2:
+ resolution: {integrity: sha512-TyaKxFIRXhODW5BTbqD/by0Gu8Z9B9AA1ki3Bzzm6fOj2b30Qlprtt+XUG52kS0zVNmxYj/WWoT0TsKiU61VOw==}
+ engines: {node: 14.* || 16.* || >= 18}
+
ember-wormhole@0.6.0:
resolution: {integrity: sha512-b7RrRxkwCBEJxM2zR34dEzIET81BOZWTcYNJtkidLycLQvdbxPys5QJEjJ/IfDikT/z5HuQBdZRKBhXI0vZNXQ==}
engines: {node: 10.* || >= 12}
@@ -7717,6 +7876,11 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ qunit@2.24.1:
+ resolution: {integrity: sha512-Eu0k/5JDjx0QnqxsE1WavnDNDgL1zgMZKsMw/AoAxnsl9p4RgyLODyo2N7abZY7CEAnvl5YUqFZdkImzbgXzSg==}
+ engines: {node: '>=10'}
+ hasBin: true
+
randombytes@2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
@@ -8439,6 +8603,10 @@ packages:
sprintf-js@1.1.3:
resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==}
+ sri-toolbox@0.2.0:
+ resolution: {integrity: sha512-DQIMWCAr/M7phwo+d3bEfXwSBEwuaJL+SJx9cuqt1Ty7K96ZFoHpYnSbhrQZEr0+0/GtmpKECP8X/R4RyeTAfw==}
+ engines: {node: '>= 0.10.4'}
+
sshpk@1.18.0:
resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==}
engines: {node: '>=0.10.0'}
@@ -9217,6 +9385,9 @@ packages:
deprecated: The library contains critical security issues and should not be used for production! The maintenance of the project has been discontinued. Consider migrating your code to isolated-vm.
hasBin: true
+ walk-sync@0.2.7:
+ resolution: {integrity: sha512-OH8GdRMowEFr0XSHQeX5fGweO6zSVHo7bG/0yJQx6LAj9Oukz0C8heI3/FYectT66gY0IPGe89kOvU410/UNpg==}
+
walk-sync@0.3.4:
resolution: {integrity: sha512-ttGcuHA/OBnN2pcM6johpYlEms7XpO5/fyKIr48541xXedan4roO8cS1Q2S/zbbjGH/BarYDAMeS2Mi9HE5Tig==}
@@ -10532,6 +10703,18 @@ snapshots:
- '@babel/core'
- supports-color
+ '@ember/render-modifiers@3.0.0(@glint/template@1.5.1)(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1))':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@embroider/macros': 1.16.9(@glint/template@1.5.1)
+ ember-cli-babel: 8.2.0(@babel/core@7.26.0)
+ ember-modifier-manager-polyfill: 1.2.0(@babel/core@7.26.0)
+ ember-source: 5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1)
+ optionalDependencies:
+ '@glint/template': 1.5.1
+ transitivePeerDependencies:
+ - supports-color
+
'@ember/string@3.1.1':
dependencies:
ember-cli-babel: 7.26.11
@@ -12565,6 +12748,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ broccoli-caching-writer@2.3.1:
+ dependencies:
+ broccoli-kitchen-sink-helpers: 0.2.9
+ broccoli-plugin: 1.1.0
+ debug: 2.6.9
+ rimraf: 2.7.1
+ rsvp: 3.6.2
+ walk-sync: 0.2.7
+ transitivePeerDependencies:
+ - supports-color
+
broccoli-caching-writer@3.0.3:
dependencies:
broccoli-kitchen-sink-helpers: 0.3.1
@@ -12688,6 +12882,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ broccoli-kitchen-sink-helpers@0.2.9:
+ dependencies:
+ glob: 5.0.15
+ mkdirp: 0.5.6
+
broccoli-kitchen-sink-helpers@0.3.1:
dependencies:
glob: 5.0.15
@@ -12794,6 +12993,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ broccoli-plugin@1.1.0:
+ dependencies:
+ promise-map-series: 0.2.3
+ quick-temp: 0.1.8
+ rimraf: 2.7.1
+ symlink-or-copy: 1.3.1
+
broccoli-plugin@1.3.1:
dependencies:
promise-map-series: 0.2.3
@@ -12870,6 +13076,16 @@ snapshots:
dependencies:
broccoli-node-api: 1.7.0
+ broccoli-sri-hash@2.1.2:
+ dependencies:
+ broccoli-caching-writer: 2.3.1
+ mkdirp: 0.5.6
+ rsvp: 3.6.2
+ sri-toolbox: 0.2.0
+ symlink-or-copy: 1.3.1
+ transitivePeerDependencies:
+ - supports-color
+
broccoli-stew@3.0.0:
dependencies:
broccoli-debug: 0.6.5
@@ -14220,6 +14436,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ ember-cli-sri@2.1.1:
+ dependencies:
+ broccoli-sri-hash: 2.1.2
+ transitivePeerDependencies:
+ - supports-color
+
ember-cli-string-utils@1.1.0: {}
ember-cli-terser@4.0.2:
@@ -14615,6 +14837,14 @@ snapshots:
- '@babel/core'
- supports-color
+ ember-page-title@8.2.4(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1)):
+ dependencies:
+ '@embroider/addon-shim': 1.8.9
+ '@simple-dom/document': 1.4.0
+ ember-source: 5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1)
+ transitivePeerDependencies:
+ - supports-color
+
ember-qunit@8.1.1(@ember/test-helpers@4.0.4(@babel/core@7.26.0)(@glint/template@1.5.1)(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1)))(@glint/template@1.5.1)(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1))(qunit@2.24.0):
dependencies:
'@ember/test-helpers': 4.0.4(@babel/core@7.26.0)(@glint/template@1.5.1)(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1))
@@ -14628,6 +14858,19 @@ snapshots:
- '@glint/template'
- supports-color
+ ember-qunit@8.1.1(@ember/test-helpers@4.0.4(@babel/core@7.26.0)(@glint/template@1.5.1)(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1)))(@glint/template@1.5.1)(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1))(qunit@2.24.1):
+ dependencies:
+ '@ember/test-helpers': 4.0.4(@babel/core@7.26.0)(@glint/template@1.5.1)(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1))
+ '@embroider/addon-shim': 1.8.9
+ '@embroider/macros': 1.16.9(@glint/template@1.5.1)
+ ember-cli-test-loader: 3.1.0
+ ember-source: 5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1)
+ qunit: 2.24.1
+ qunit-theme-ember: 1.0.0
+ transitivePeerDependencies:
+ - '@glint/template'
+ - supports-color
+
ember-raf-scheduler@0.3.0:
dependencies:
ember-cli-babel: 7.26.11
@@ -14693,6 +14936,18 @@ snapshots:
- '@babel/core'
- supports-color
+ ember-sinon-qunit@7.5.0(@babel/core@7.26.0)(ember-source@5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1))(qunit@2.24.1)(sinon@15.2.0):
+ dependencies:
+ '@embroider/addon-shim': 1.8.9
+ '@types/sinon': 17.0.3
+ decorator-transforms: 2.2.2(@babel/core@7.26.0)
+ ember-source: 5.12.0(@glimmer/component@1.1.2(@babel/core@7.26.0))(@glint/template@1.5.1)(rsvp@4.8.5)(webpack@5.97.1)
+ qunit: 2.24.1
+ sinon: 15.2.0
+ transitivePeerDependencies:
+ - '@babel/core'
+ - supports-color
+
ember-source-channel-url@3.0.0(encoding@0.1.13):
dependencies:
node-fetch: 2.7.0(encoding@0.1.13)
@@ -14897,6 +15152,12 @@ snapshots:
- encoding
- supports-color
+ ember-welcome-page@7.0.2:
+ dependencies:
+ '@embroider/addon-shim': 1.8.9
+ transitivePeerDependencies:
+ - supports-color
+
ember-wormhole@0.6.0:
dependencies:
ember-cli-babel: 7.26.11
@@ -18679,6 +18940,12 @@ snapshots:
node-watch: 0.7.3
tiny-glob: 0.2.9
+ qunit@2.24.1:
+ dependencies:
+ commander: 7.2.0
+ node-watch: 0.7.3
+ tiny-glob: 0.2.9
+
randombytes@2.1.0:
dependencies:
safe-buffer: 5.2.1
@@ -19594,6 +19861,8 @@ snapshots:
sprintf-js@1.1.3: {}
+ sri-toolbox@0.2.0: {}
+
sshpk@1.18.0:
dependencies:
asn1: 0.2.6
@@ -20560,6 +20829,11 @@ snapshots:
acorn: 8.12.1
acorn-walk: 8.3.4
+ walk-sync@0.2.7:
+ dependencies:
+ ensure-posix-path: 1.1.1
+ matcher-collection: 1.1.2
+
walk-sync@0.3.4:
dependencies:
ensure-posix-path: 1.1.1
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index a694fdd9da..ecdf393257 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,3 +1,4 @@
packages:
- .
- ember_debug
+ - test-apps/*
diff --git a/test-apps/classic/.ember-cli b/test-apps/classic/.ember-cli
new file mode 100644
index 0000000000..4defd284ec
--- /dev/null
+++ b/test-apps/classic/.ember-cli
@@ -0,0 +1,7 @@
+{
+ /**
+ Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript
+ rather than JavaScript by default, when a TypeScript version of a given blueprint is available.
+ */
+ "isTypeScriptProject": true
+}
diff --git a/test-apps/classic/app/app.js b/test-apps/classic/app/app.js
new file mode 100644
index 0000000000..19f2ce27d7
--- /dev/null
+++ b/test-apps/classic/app/app.js
@@ -0,0 +1,14 @@
+import Application from '@ember/application';
+import Resolver from 'ember-resolver';
+import loadInitializers from 'ember-load-initializers';
+import config from 'test-app/config/environment';
+
+export default class App extends Application {
+ modulePrefix = config.modulePrefix;
+ podModulePrefix = config.podModulePrefix;
+ Resolver = Resolver;
+}
+
+console.log('test app');
+
+loadInitializers(App, config.modulePrefix);
diff --git a/test-apps/classic/app/components/.gitkeep b/test-apps/classic/app/components/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test-apps/classic/app/controllers/.gitkeep b/test-apps/classic/app/controllers/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test-apps/classic/app/helpers/.gitkeep b/test-apps/classic/app/helpers/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test-apps/classic/app/index.html b/test-apps/classic/app/index.html
new file mode 100644
index 0000000000..90cb9a37c0
--- /dev/null
+++ b/test-apps/classic/app/index.html
@@ -0,0 +1,24 @@
+
+
+
+
+ TestApp
+
+
+
+ {{content-for "head"}}
+
+
+
+
+ {{content-for "head-footer"}}
+
+
+ {{content-for "body"}}
+
+
+
+
+ {{content-for "body-footer"}}
+
+
diff --git a/test-apps/classic/app/models/.gitkeep b/test-apps/classic/app/models/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test-apps/classic/app/router.js b/test-apps/classic/app/router.js
new file mode 100644
index 0000000000..38a0b80a63
--- /dev/null
+++ b/test-apps/classic/app/router.js
@@ -0,0 +1,9 @@
+import EmberRouter from '@ember/routing/router';
+import config from 'test-app/config/environment';
+
+export default class Router extends EmberRouter {
+ location = config.locationType;
+ rootURL = config.rootURL;
+}
+
+Router.map(function () {});
diff --git a/test-apps/classic/app/routes/.gitkeep b/test-apps/classic/app/routes/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test-apps/classic/app/services/adapters/basic.js b/test-apps/classic/app/services/adapters/basic.js
new file mode 100644
index 0000000000..9fa13c3a9b
--- /dev/null
+++ b/test-apps/classic/app/services/adapters/basic.js
@@ -0,0 +1,156 @@
+/**
+ * The adapter stores logic specific to each environment.
+ * Extend this object with env specific code (such as chrome/firefox/test),
+ * then set the application's `adapter` property to the name of this adapter.
+ *
+ * example:
+ *
+ * ```javascript
+ * const EmberInspector = App.Create({
+ * adapter: 'chrome'
+ * });
+ * ```
+ */
+import Service from '@ember/service';
+import { action } from '@ember/object';
+import { tracked } from '@glimmer/tracking';
+
+const config = {};
+
+export default class Basic extends Service {
+ _messageCallbacks;
+ name = 'basic';
+
+ @tracked canOpenResource = false;
+
+ /**
+ * Called when the adapter is created (when
+ * the inspector app boots).
+ */
+ constructor() {
+ super(...arguments);
+
+ this._messageCallbacks = [];
+ this._checkVersion();
+ }
+
+ /**
+ * Listens to Ember Inspector message about
+ * Ember version mismatch. If a mismatch message is received
+ * it means the current inspector app does not support the current
+ * Ember version and needs to switch to an inspector version
+ * that does.
+ *
+ * @private
+ */
+ _checkVersion() {
+ this.onMessageReceived((message) => {
+ const { name, version } = message;
+ if (name === 'version-mismatch') {
+ const previousVersions = config.previousEmberVersionsSupported;
+ const [fromVersion, tillVersion] = config.emberVersionsSupported;
+ let neededVersion;
+
+ if (compareVersion(version, fromVersion) === -1) {
+ neededVersion = previousVersions[previousVersions.length - 1];
+ } else if (tillVersion && compareVersion(version, tillVersion) !== -1) {
+ neededVersion = tillVersion;
+ } else {
+ return;
+ }
+ this.onVersionMismatch(neededVersion);
+ }
+ });
+ this.sendMessage({ type: 'check-version', from: 'devtools' });
+ }
+
+ /**
+ * Hook called when the Ember version is not
+ * supported by the current inspector version.
+ *
+ * Each adapter should implement this hook
+ * to switch to an older/new inspector version
+ * that supports this Ember version.
+ *
+ * @param _neededVersion (The version to go to)
+ */
+ onVersionMismatch() {}
+
+ /**
+ Used to send messages to EmberDebug
+
+ @param _message the message to send
+ **/
+ sendMessage() {}
+
+ /**
+ Register functions to be called
+ when a message from EmberDebug is received
+ **/
+ onMessageReceived(callback) {
+ this._messageCallbacks.push(callback);
+ }
+
+ _messageReceived(...args) {
+ this._messageCallbacks.forEach((callback) => {
+ callback(...args);
+ });
+ }
+
+ reloadTab() {}
+ // Called when the "Reload" is clicked by the user
+ willReload() {}
+ openResource() {}
+
+ @action
+ refreshPage() {
+ // If the adapter defined a `reloadTab` method, it means
+ // they prefer to handle the reload themselves
+ if (typeof this.reloadTab === 'function') {
+ this.reloadTab();
+ } else {
+ // inject ember_debug as quickly as possible in chrome
+ // so that promises created on dom ready are caught
+ this.port.send('general:refresh');
+ this.willReload();
+ }
+ }
+}
+
+/**
+ * Compares two Ember versions.
+ *
+ * Returns:
+ * `-1` if version < version
+ * 0 if version1 == version2
+ * 1 if version1 > version2
+ *
+ * @return result of the comparison
+ */
+function compareVersion(version1, version2) {
+ const v1 = cleanupVersion(version1).split('.');
+ const v2 = cleanupVersion(version2).split('.');
+ for (let i = 0; i < 3; i++) {
+ // @ts-expect-error TODO: refactor this to make TS happy
+ const compared = compare(+v1[i], +v2[i]);
+ if (compared !== 0) {
+ return compared;
+ }
+ }
+ return 0;
+}
+
+/* Remove -alpha, -beta, etc from versions */
+function cleanupVersion(version) {
+ return version.replace(/-.*/g, '');
+}
+
+function compare(val, number) {
+ if (val === number) {
+ return 0;
+ } else if (val < number) {
+ return -1;
+ } else if (val > number) {
+ return 1;
+ }
+}
diff --git a/test-apps/classic/app/services/adapters/web-extension.js b/test-apps/classic/app/services/adapters/web-extension.js
new file mode 100644
index 0000000000..e1d888fbbf
--- /dev/null
+++ b/test-apps/classic/app/services/adapters/web-extension.js
@@ -0,0 +1,163 @@
+import { tracked } from '@glimmer/tracking';
+
+import BasicAdapter from './basic';
+
+let emberDebug = null;
+let config = {
+ emberVersionsSupported: ['3.16.0'],
+};
+
+export default class WebExtension extends BasicAdapter {
+ @tracked canOpenResource = false;
+ name = 'web-extension';
+
+ /**
+ * Called when the adapter is created.
+ */
+ constructor(...args) {
+ super(...args);
+
+ this._connect();
+ this._handleReload();
+ this._setThemeColors();
+
+ void Promise.resolve().then(() => this._sendEmberDebug());
+ }
+
+ sendMessage(message) {
+ this._chromePort.postMessage(message ?? {});
+ }
+
+ _sendEmberDebug() {
+ const minimumVersion = config.emberVersionsSupported[0].replace(/\./g, '-');
+ const url = chrome.runtime.getURL(
+ `/panes-${minimumVersion}/ember_debug.js`,
+ );
+ // first send to all frames in current tab
+ this.sendMessage({
+ from: 'devtools',
+ tabId: chrome.devtools.inspectedWindow.tabId,
+ type: 'inject-ember-debug',
+ value: url,
+ });
+ this.onMessageReceived((message, sender) => {
+ if (message === 'ember-content-script-ready') {
+ this.sendMessage({
+ frameId: sender.frameId,
+ from: 'devtools',
+ tabId: chrome.devtools.inspectedWindow.tabId,
+ type: 'inject-ember-debug',
+ value: url,
+ });
+ }
+ });
+ }
+
+ get _chromePort() {
+ return chrome.runtime.connect();
+ }
+
+ _connect() {
+ const chromePort = this._chromePort;
+ chromePort.postMessage({ appId: chrome.devtools.inspectedWindow.tabId });
+
+ chromePort.onMessage.addListener((...args) => {
+ this._messageReceived(...args);
+ });
+
+ chromePort.onDisconnect.addListener(() => {
+ this._connect();
+ });
+ }
+
+ _handleReload() {
+ chrome.devtools.network.onNavigated.addListener(() => {
+ this._injectDebugger();
+ location.reload();
+ });
+ }
+
+ _injectDebugger() {
+ void loadEmberDebug().then((emberDebug) => {
+ chrome.devtools.inspectedWindow.eval(emberDebug, (success, error) => {
+ if (success === undefined && error) {
+ throw error;
+ }
+ });
+ });
+ }
+
+ _setThemeColors() {
+ // Remove old theme colors to ensure switching themes works
+ document.body.classList.remove('theme-light', 'theme-dark');
+
+ let theme = 'theme-light';
+ if (chrome.devtools.panels.themeName === 'dark') {
+ theme = 'theme-dark';
+ }
+ document.body.classList.add(theme);
+ }
+
+ willReload() {
+ this._injectDebugger();
+ }
+
+ /**
+ * Open the devtools "Elements" or "Sources" tab and select a specific DOM node or function.
+ */
+ inspectJSValue(name) {
+ chrome.devtools.inspectedWindow.eval(`
+ inspect(window[${JSON.stringify(name)}]);
+ delete window[${JSON.stringify(name)}];
+ `);
+ }
+
+ /**
+ * Redirect to the correct inspector version.
+ */
+ onVersionMismatch(goToVersion) {
+ window.location.href = `../panes-${goToVersion.replace(
+ /\./g,
+ '-',
+ )}/index.html`;
+ }
+
+ /**
+ We handle the reload here so we can inject
+ scripts as soon as possible into the new page.
+ */
+ reloadTab() {
+ void loadEmberDebug().then((emberDebug) => {
+ chrome.devtools.inspectedWindow.reload({
+ injectedScript: emberDebug,
+ });
+ });
+ }
+}
+
+function loadEmberDebug() {
+ const minimumVersion = config.emberVersionsSupported[0].replace(/\./g, '-');
+ let xhr;
+
+ return new Promise((resolve) => {
+ if (!emberDebug) {
+ xhr = new XMLHttpRequest();
+ xhr.open(
+ 'GET',
+ chrome.runtime.getURL(`/panes-${minimumVersion}/ember_debug.js`),
+ );
+ xhr.onload = function () {
+ if (xhr.readyState === 4) {
+ if (xhr.status === 200) {
+ emberDebug = xhr.responseText;
+ resolve(emberDebug);
+ }
+ }
+ };
+
+ xhr.send();
+ } else {
+ resolve(emberDebug);
+ }
+ });
+}
diff --git a/test-apps/classic/app/styles/app.css b/test-apps/classic/app/styles/app.css
new file mode 100644
index 0000000000..2763afa4cf
--- /dev/null
+++ b/test-apps/classic/app/styles/app.css
@@ -0,0 +1 @@
+/* Ember supports plain CSS out of the box. More info: https://cli.emberjs.com/release/advanced-use/stylesheets/ */
diff --git a/test-apps/classic/app/templates/application.hbs b/test-apps/classic/app/templates/application.hbs
new file mode 100644
index 0000000000..d6565bbd6b
--- /dev/null
+++ b/test-apps/classic/app/templates/application.hbs
@@ -0,0 +1,7 @@
+{{page-title "TestApp"}}
+
+{{outlet}}
+
+{{! The following component displays Ember's default welcome message. }}
+
+{{! Feel free to remove this! }}
\ No newline at end of file
diff --git a/test-apps/classic/config/ember-cli-update.json b/test-apps/classic/config/ember-cli-update.json
new file mode 100644
index 0000000000..5dc0d1493e
--- /dev/null
+++ b/test-apps/classic/config/ember-cli-update.json
@@ -0,0 +1,20 @@
+{
+ "schemaVersion": "1.0.0",
+ "packages": [
+ {
+ "name": "ember-cli",
+ "version": "6.1.0",
+ "blueprints": [
+ {
+ "name": "app",
+ "outputRepo": "https://github.com/ember-cli/ember-new-output",
+ "codemodsSource": "ember-app-codemods-manifest@1",
+ "isBaseBlueprint": true,
+ "options": [
+ "--ci-provider=github"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/config/ember-try.js b/test-apps/classic/config/ember-try.js
similarity index 94%
rename from config/ember-try.js
rename to test-apps/classic/config/ember-try.js
index 4471528f9f..5cae0d8085 100644
--- a/config/ember-try.js
+++ b/test-apps/classic/config/ember-try.js
@@ -12,7 +12,6 @@ module.exports = async function () {
devDependencies: {
'@ember/test-helpers': '^2.4.0',
'ember-cli': '^3.28.0',
- 'ember-cli-app-version': '^5.0.0',
'ember-source': '~3.16.0',
'ember-resolver': '^11.0.1',
'ember-qunit': '^5.1.5',
@@ -25,7 +24,6 @@ module.exports = async function () {
devDependencies: {
'@ember/test-helpers': '^2.4.0',
'ember-cli': '^3.28.0',
- 'ember-cli-app-version': '^5.0.0',
'ember-source': '~3.20.5',
'ember-resolver': '^11.0.1',
'ember-qunit': '^5.1.5',
@@ -38,7 +36,6 @@ module.exports = async function () {
devDependencies: {
'@ember/test-helpers': '^2.4.0',
'ember-cli': '^3.28.0',
- 'ember-cli-app-version': '^5.0.0',
'ember-source': '~3.24.0',
'ember-resolver': '^11.0.1',
'ember-qunit': '^5.1.5',
@@ -51,7 +48,6 @@ module.exports = async function () {
devDependencies: {
'@ember/test-helpers': '^2.4.0',
'ember-cli': '^3.28.0',
- 'ember-cli-app-version': '^6.0.0',
'ember-source': '~3.28.0',
'ember-resolver': '^11.0.1',
'ember-qunit': '^5.1.5',
diff --git a/test-apps/classic/config/environment.js b/test-apps/classic/config/environment.js
new file mode 100644
index 0000000000..113d30aeb0
--- /dev/null
+++ b/test-apps/classic/config/environment.js
@@ -0,0 +1,48 @@
+'use strict';
+
+module.exports = function (environment) {
+ const ENV = {
+ modulePrefix: 'test-app',
+ environment,
+ rootURL: '/',
+ locationType: 'history',
+ EmberENV: {
+ EXTEND_PROTOTYPES: false,
+ FEATURES: {
+ // Here you can enable experimental features on an ember canary build
+ // e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true
+ },
+ },
+
+ APP: {
+ // Here you can pass flags/options to your application instance
+ // when it is created
+ },
+ };
+
+ if (environment === 'development') {
+ // ENV.APP.LOG_RESOLVER = true;
+ // ENV.APP.LOG_ACTIVE_GENERATION = true;
+ // ENV.APP.LOG_TRANSITIONS = true;
+ // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
+ // ENV.APP.LOG_VIEW_LOOKUPS = true;
+ }
+
+ if (environment === 'test') {
+ // Testem prefers this...
+ ENV.locationType = 'none';
+
+ // keep test console output quieter
+ ENV.APP.LOG_ACTIVE_GENERATION = false;
+ ENV.APP.LOG_VIEW_LOOKUPS = false;
+
+ ENV.APP.rootElement = '#ember-testing';
+ ENV.APP.autoboot = false;
+ }
+
+ if (environment === 'production') {
+ // here you can enable a production-specific feature
+ }
+
+ return ENV;
+};
diff --git a/test-apps/classic/config/optional-features.json b/test-apps/classic/config/optional-features.json
new file mode 100644
index 0000000000..5329dd9913
--- /dev/null
+++ b/test-apps/classic/config/optional-features.json
@@ -0,0 +1,7 @@
+{
+ "application-template-wrapper": false,
+ "default-async-observers": true,
+ "jquery-integration": false,
+ "template-only-glimmer-components": true,
+ "no-implicit-route-model": true
+}
diff --git a/test-apps/classic/config/targets.js b/test-apps/classic/config/targets.js
new file mode 100644
index 0000000000..1e48e0599f
--- /dev/null
+++ b/test-apps/classic/config/targets.js
@@ -0,0 +1,11 @@
+'use strict';
+
+const browsers = [
+ 'last 1 Chrome versions',
+ 'last 1 Firefox versions',
+ 'last 1 Safari versions',
+];
+
+module.exports = {
+ browsers,
+};
diff --git a/test-apps/classic/ember-cli-build.js b/test-apps/classic/ember-cli-build.js
new file mode 100644
index 0000000000..c11fc2e743
--- /dev/null
+++ b/test-apps/classic/ember-cli-build.js
@@ -0,0 +1,25 @@
+'use strict';
+
+const EmberApp = require('ember-cli/lib/broccoli/ember-app');
+const path = require('path');
+const fs = require('fs');
+const { Funnel } = require('broccoli-funnel');
+
+const testingDir = path.resolve(__dirname, '../../dist/testing');
+const distDir = path.resolve(__dirname, '../../dist');
+const testingFolderExists = fs.existsSync(testingDir);
+
+module.exports = function (defaults) {
+ defaults.project.name = () => 'test-app';
+ const app = new EmberApp(defaults, {
+ 'ember-cli-babel': { enableTypeScriptTransform: true },
+ trees: {
+ tests: new Funnel(path.resolve(__dirname, '../tests')),
+ public: new Funnel(testingFolderExists ? testingDir : distDir, {
+ files: ['background.js', 'content-script.js', 'panes-3-16-0'],
+ }),
+ },
+ });
+
+ return app.toTree();
+};
diff --git a/test-apps/classic/package.json b/test-apps/classic/package.json
new file mode 100644
index 0000000000..47edbf9b23
--- /dev/null
+++ b/test-apps/classic/package.json
@@ -0,0 +1,68 @@
+{
+ "name": "classic-test-app",
+ "version": "0.0.0",
+ "private": true,
+ "description": "Small description for test-app goes here",
+ "repository": "",
+ "license": "MIT",
+ "author": "",
+ "directories": {
+ "doc": "doc",
+ "test": "tests"
+ },
+ "scripts": {
+ "build": "ember build --environment=testing",
+ "test": "EMBER_ENV=test ember test",
+ "ember-debug-test": "pnpm test",
+ "ember:try:one": "ember try:one",
+ "test-server:ember": "ember test --serve --watcher node --launch="
+ },
+ "devDependencies": {
+ "@babel/core": "^7.26.0",
+ "@babel/eslint-parser": "^7.25.9",
+ "@babel/plugin-proposal-decorators": "^7.25.9",
+ "@ember/optional-features": "^2.2.0",
+ "@ember/string": "^4.0.0",
+ "@ember/test-helpers": "^4.0.4",
+ "@eslint/js": "^9.17.0",
+ "@glimmer/component": "^1.1.2",
+ "@glimmer/tracking": "^1.1.2",
+ "broccoli-asset-rev": "^3.0.0",
+ "concurrently": "^9.1.0",
+ "ember-auto-import": "^2.10.0",
+ "ember-cli": "~6.1.0",
+ "ember-cli-babel": "^8.2.0",
+ "ember-cli-clean-css": "^3.0.0",
+ "ember-cli-dependency-checker": "^3.3.3",
+ "ember-cli-htmlbars": "^6.3.0",
+ "ember-cli-inject-live-reload": "^2.1.0",
+ "ember-cli-sri": "^2.1.1",
+ "ember-cli-terser": "^4.0.2",
+ "ember-fetch": "^8.1.2",
+ "ember-load-initializers": "^3.0.1",
+ "ember-modifier": "^4.2.0",
+ "ember-page-title": "^8.2.3",
+ "ember-qunit": "^8.1.1",
+ "@ember/render-modifiers": "^3.0.0",
+ "qunit": "^2.24.1",
+ "qunit-dom": "^3.4.0",
+ "ember-sinon-qunit": "^7.5.0",
+ "ember-resolver": "^13.1.0",
+ "ember-source": "^5.0.0",
+ "ember-template-lint": "^6.0.0",
+ "ember-welcome-page": "^7.0.2",
+ "ember-wormhole": "^0.6.0",
+ "ember-try": "^3.0.0",
+ "loader.js": "^4.7.0",
+ "tracked-built-ins": "^3.4.0",
+ "ember-in-element-polyfill": "^1.0.1",
+ "webpack": "^5.97.1",
+ "ember-debug": "workspace:*"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "ember": {
+ "edition": "octane"
+ }
+}
diff --git a/test-apps/classic/testem.js b/test-apps/classic/testem.js
new file mode 100644
index 0000000000..ed2f37124a
--- /dev/null
+++ b/test-apps/classic/testem.js
@@ -0,0 +1,23 @@
+'use strict';
+
+module.exports = {
+ test_page: 'tests/index.html?hidepassed',
+ disable_watching: true,
+ launch_in_ci: ['Chrome'],
+ launch_in_dev: ['Chrome'],
+ browser_start_timeout: 120,
+ browser_args: {
+ Chrome: {
+ ci: [
+ // --no-sandbox is needed when running Chrome inside a container
+ process.env.CI ? '--no-sandbox' : null,
+ '--headless',
+ '--disable-dev-shm-usage',
+ '--disable-software-rasterizer',
+ '--mute-audio',
+ '--remote-debugging-port=0',
+ '--window-size=1440,900',
+ ].filter(Boolean),
+ },
+ },
+};
diff --git a/test-apps/embroider-static-source/tests b/test-apps/embroider-static-source/tests
new file mode 120000
index 0000000000..6dd24e02b5
--- /dev/null
+++ b/test-apps/embroider-static-source/tests
@@ -0,0 +1 @@
+../tests
\ No newline at end of file
diff --git a/tests/ember_debug/container-debug-test.js b/test-apps/tests/ember_debug/container-debug-test.js
similarity index 100%
rename from tests/ember_debug/container-debug-test.js
rename to test-apps/tests/ember_debug/container-debug-test.js
diff --git a/tests/ember_debug/deprecation-debug-test.js b/test-apps/tests/ember_debug/deprecation-debug-test.js
similarity index 100%
rename from tests/ember_debug/deprecation-debug-test.js
rename to test-apps/tests/ember_debug/deprecation-debug-test.js
diff --git a/tests/ember_debug/ember-data-test.js b/test-apps/tests/ember_debug/ember-data-test.js
similarity index 100%
rename from tests/ember_debug/ember-data-test.js
rename to test-apps/tests/ember_debug/ember-data-test.js
diff --git a/tests/ember_debug/ember-debug-test.js b/test-apps/tests/ember_debug/ember-debug-test.js
similarity index 100%
rename from tests/ember_debug/ember-debug-test.js
rename to test-apps/tests/ember_debug/ember-debug-test.js
diff --git a/tests/ember_debug/object-inspector-test.js b/test-apps/tests/ember_debug/object-inspector-test.js
similarity index 100%
rename from tests/ember_debug/object-inspector-test.js
rename to test-apps/tests/ember_debug/object-inspector-test.js
diff --git a/tests/ember_debug/profile-manager-test.js b/test-apps/tests/ember_debug/profile-manager-test.js
similarity index 100%
rename from tests/ember_debug/profile-manager-test.js
rename to test-apps/tests/ember_debug/profile-manager-test.js
diff --git a/tests/ember_debug/profile-node-test.js b/test-apps/tests/ember_debug/profile-node-test.js
similarity index 100%
rename from tests/ember_debug/profile-node-test.js
rename to test-apps/tests/ember_debug/profile-node-test.js
diff --git a/tests/ember_debug/promise-assembler-test.js b/test-apps/tests/ember_debug/promise-assembler-test.js
similarity index 100%
rename from tests/ember_debug/promise-assembler-test.js
rename to test-apps/tests/ember_debug/promise-assembler-test.js
diff --git a/tests/ember_debug/promise-debug-test.js b/test-apps/tests/ember_debug/promise-debug-test.js
similarity index 100%
rename from tests/ember_debug/promise-debug-test.js
rename to test-apps/tests/ember_debug/promise-debug-test.js
diff --git a/tests/ember_debug/render-debug-test.js b/test-apps/tests/ember_debug/render-debug-test.js
similarity index 100%
rename from tests/ember_debug/render-debug-test.js
rename to test-apps/tests/ember_debug/render-debug-test.js
diff --git a/tests/ember_debug/route-debug-test.js b/test-apps/tests/ember_debug/route-debug-test.js
similarity index 100%
rename from tests/ember_debug/route-debug-test.js
rename to test-apps/tests/ember_debug/route-debug-test.js
diff --git a/tests/ember_debug/view-debug-test.js b/test-apps/tests/ember_debug/view-debug-test.js
similarity index 100%
rename from tests/ember_debug/view-debug-test.js
rename to test-apps/tests/ember_debug/view-debug-test.js
diff --git a/test-apps/tests/helpers/index.ts b/test-apps/tests/helpers/index.ts
new file mode 100644
index 0000000000..e190f567ed
--- /dev/null
+++ b/test-apps/tests/helpers/index.ts
@@ -0,0 +1,43 @@
+import {
+ setupApplicationTest as upstreamSetupApplicationTest,
+ setupRenderingTest as upstreamSetupRenderingTest,
+ setupTest as upstreamSetupTest,
+ type SetupTestOptions,
+} from 'ember-qunit';
+
+// This file exists to provide wrappers around ember-qunit's
+// test setup functions. This way, you can easily extend the setup that is
+// needed per test type.
+
+function setupApplicationTest(hooks: NestedHooks, options?: SetupTestOptions) {
+ upstreamSetupApplicationTest(hooks, options);
+
+ // Additional setup for application tests can be done here.
+ //
+ // For example, if you need an authenticated session for each
+ // application test, you could do:
+ //
+ // hooks.beforeEach(async function () {
+ // await authenticateSession(); // ember-simple-auth
+ // });
+ //
+ // This is also a good place to call test setup functions coming
+ // from other addons:
+ //
+ // setupIntl(hooks, 'en-us'); // ember-intl
+ // setupMirage(hooks); // ember-cli-mirage
+}
+
+function setupRenderingTest(hooks: NestedHooks, options?: SetupTestOptions) {
+ upstreamSetupRenderingTest(hooks, options);
+
+ // Additional setup for rendering tests can be done here.
+}
+
+function setupTest(hooks: NestedHooks, options?: SetupTestOptions) {
+ upstreamSetupTest(hooks, options);
+
+ // Additional setup for unit tests can be done here.
+}
+
+export { setupApplicationTest, setupRenderingTest, setupTest };
diff --git a/tests/helpers/setup-ember-debug-test.js b/test-apps/tests/helpers/setup-ember-debug-test.js
similarity index 68%
rename from tests/helpers/setup-ember-debug-test.js
rename to test-apps/tests/helpers/setup-ember-debug-test.js
index 0e742d5ef7..37eb22d746 100644
--- a/tests/helpers/setup-ember-debug-test.js
+++ b/test-apps/tests/helpers/setup-ember-debug-test.js
@@ -10,10 +10,7 @@ import {
teardownContext,
} from '@ember/test-helpers';
import { run } from '@ember/runloop';
-import Route from '@ember/routing/route';
-import Controller from '@ember/controller';
-import BasicAdapter from 'ember-inspector/services/adapters/basic';
-import config from 'ember-inspector/config/environment';
+import config from 'test-app/config/environment';
import { hbs } from 'ember-cli-htmlbars';
import EmberDebugImport from 'ember-debug/main';
@@ -58,17 +55,6 @@ export default function setupEmberDebugTest(hooks, options = {}) {
}
this.owner.register('router:main', Router);
- this.owner.register('service:adapter', BasicAdapter);
- /**
- * preferably, ember debug tests should use their own test app
- * but currently its mangled with the inspector ui app, which is not compatible with all ember versions being tested.
- * we do filter the tests to only run the ember_debug tests, but that does not prevent the app merging.
- * The application route/controller/template of inspector ui was being indirectly used in ember_debug tests,
- * which is not required and broke older lts tests
- */
- this.owner.register('route:application', class extends Route {});
- this.owner.register('controller:application', class extends Controller {});
- this.owner.register('template:application', hbs('{{outlet}}'));
run(() => {
EmberDebug.isTesting = true;
diff --git a/test-apps/tests/index.html b/test-apps/tests/index.html
new file mode 100644
index 0000000000..21b1db8db9
--- /dev/null
+++ b/test-apps/tests/index.html
@@ -0,0 +1,64 @@
+
+
+
+
+ EmberInspector Tests
+
+
+
+
+
+ {{content-for "head"}}
+ {{content-for "test-head"}}
+
+
+
+
+
+ {{content-for "head-footer"}}
+ {{content-for "test-head-footer"}}
+
+
+
+ {{content-for "body"}}
+ {{content-for "test-body"}}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{content-for "body-footer"}}
+ {{content-for "test-body-footer"}}
+
+
diff --git a/tests/integration/injection-test.js b/test-apps/tests/integration/injection-test.js
similarity index 99%
rename from tests/integration/injection-test.js
rename to test-apps/tests/integration/injection-test.js
index f9bfb6b86f..8112d32277 100644
--- a/tests/integration/injection-test.js
+++ b/test-apps/tests/integration/injection-test.js
@@ -135,7 +135,7 @@ class ChromeApi {
if (url.startsWith('/')) {
url = url.slice(1);
}
- return '/testing/' + url;
+ return '/' + url;
},
connect() {
const other = self.connectToOther;
diff --git a/test-apps/tests/test-adapter.js b/test-apps/tests/test-adapter.js
new file mode 100644
index 0000000000..283b5204b4
--- /dev/null
+++ b/test-apps/tests/test-adapter.js
@@ -0,0 +1,348 @@
+import QUnit from 'qunit';
+import { next } from '@ember/runloop';
+import BasicAdapter from 'test-app/services/adapters/basic';
+import { settled } from '@ember/test-helpers';
+
+let adapter = null;
+let resourcesEnabled = false;
+let resources = [];
+let responders = [];
+
+export function setupTestAdapter(hooks) {
+ // Some default responders that are part of the normal application boot cycle
+ hooks.beforeEach(function () {
+ respondWith('check-version', false, { isDefault: true });
+
+ respondWith(
+ 'general:applicationBooted',
+ {
+ type: 'general:applicationBooted',
+ applicationId: 'my-app',
+ applicationName: 'My App',
+ booted: true,
+ },
+ { isDefault: true },
+ );
+
+ respondWith(
+ 'app-picker-loaded',
+ {
+ type: 'apps-loaded',
+ applicationId: null,
+ applicationName: null,
+ apps: [
+ {
+ applicationId: 'my-app',
+ applicationName: 'My App',
+ },
+ ],
+ },
+ { isDefault: true },
+ );
+
+ respondWith('app-selected', false, { isDefault: true });
+
+ respondWith(
+ 'deprecation:getCount',
+ ({ applicationId, applicationName }) => ({
+ type: 'deprecation:count',
+ applicationId,
+ applicationName,
+ count: 0,
+ }),
+ { isDefault: true },
+ );
+ });
+
+ // Ensure all expectations are met and reset the global states
+ hooks.afterEach(function (assert) {
+ for (let { file, line, actual, expected, reject } of resources) {
+ if (!isNaN(expected) && actual !== expected) {
+ assert.strictEqual(
+ actual,
+ expected,
+ `Expceting resouce ${file}:${line} to be opened ${expected} time(s)`,
+ );
+ reject(
+ `Expceting resouce ${file}:${line} to be opened ${expected} time(s), was opened ${actual} time(s)`,
+ );
+ }
+ }
+
+ for (let { type, isDefault, actual, expected, reject } of responders) {
+ if (!isDefault && !isNaN(expected) && actual !== expected) {
+ assert.strictEqual(
+ actual,
+ expected,
+ `The correct amount of ${type} messages are sent`,
+ );
+ reject(`Expecting ${expected} ${type} messages, got ${actual}`);
+ }
+ }
+
+ adapter = null;
+ resourcesEnabled = false;
+ resources.length = 0;
+ responders.length = 0;
+ });
+}
+
+/**
+ * Allow `openResouce` to be called on the adapter.
+ *
+ * @method enableOpenResource
+ */
+export function enableOpenResource() {
+ resourcesEnabled = true;
+}
+
+/**
+ * Expect `openResouce` to be called on the adapter with a specific filename and
+ * line number. Must call `enableOpenResource` first.
+ *
+ * @method expectOpenResource
+ * @param {String} file The filename.
+ * @param {number} line The line number.
+ * @param {Object} options
+ * - {number | false} count How many calls to allow. `false` for unlimited.
+ * Defaults to 1.
+ * @return {Promise} Resolves when all the expected calls are made, or
+ * rejects at the end of the current test if not called
+ * enough times.
+ */
+export function expectOpenResource(file, line, options = {}) {
+ if (!resourcesEnabled) {
+ throw new Error('call enableOpenResource first');
+ }
+
+ return new Promise((resolve, reject) => {
+ let { count } = { count: 1, ...options };
+ resources.push({
+ file,
+ line,
+ actual: 0,
+ expected: count === false ? NaN : count,
+ resolve,
+ reject,
+ });
+ });
+}
+
+/**
+ * Send a message to the adapter.
+ *
+ * @method expectOpenResource
+ * @param {Object} message The message.
+ * @return {Promise} Resolves when the message is delivered.
+ */
+export async function sendMessage(message) {
+ if (adapter === null) {
+ throw new Error('Cannot call sendMessage outside of a test');
+ }
+
+ const msg = await new Promise((resolve, reject) => {
+ // eslint-disable-next-line ember/no-runloop
+ next(async () => {
+ let normalized = {
+ applicationId: 'my-app',
+ applicationName: 'My App',
+ ...message,
+ from: 'inspectedWindow',
+ };
+ try {
+ adapter._messageReceived(normalized);
+ } catch (e) {
+ return reject(e);
+ }
+
+ resolve(normalized);
+ });
+ });
+
+ await settled();
+ return msg;
+}
+
+/**
+ * Expect a message from the adapter of the given type, and respond to the message
+ * with the given payload.
+ *
+ * @method respondWith
+ * @param {String} type The incoming message type.
+ * @param { false | Object | Function } payload The payload.
+ * - Pass `false` to acknoledge the message but don't send a response.
+ * - Pass an object to send a response (`message` parameter of `sendMessage`).
+ * - Pass a callback to dynamically respond with one of the above, or `undefined`,
+ * in which case the incoming messages is considered unhandled and the remaining
+ * responders will be tried instead. The callback is given the incoming message
+ * as an argument.
+ * @param {Object} options
+ * - {number | false} count How many calls to allow. `false` for unlimited.
+ * Defaults to 1.
+ * @return {Promise} Resolves when all the expected calls are made, or
+ * rejects at the end of the current test if not called
+ * enough times.
+ */
+export function respondWith(type, payload, options = {}) {
+ return new Promise((resolve, reject) => {
+ let { count, isDefault } = { count: 1, isDefault: false, ...options };
+ let callback = typeof payload === 'function' ? payload : () => payload;
+
+ responders.push({
+ type,
+ isDefault,
+ callback,
+ actual: 0,
+ expected: count === false ? NaN : count,
+ resolve,
+ reject,
+ });
+ });
+}
+
+/**
+ * Disable the default responder for the given type.
+ *
+ * @method disableDefaultResponseFor
+ */
+export function disableDefaultResponseFor(type) {
+ for (let [i, responder] of responders.entries()) {
+ if (responder.type === type && responder.isDefault) {
+ if (responder.actual > 0) {
+ throw new Error(
+ `Cannot remove default responder for ${type}: a response has already been sent!`,
+ );
+ }
+
+ responders.splice(i, 1);
+ return;
+ }
+ }
+
+ throw new Error(
+ `Cannot remove default responder for ${type}: no such responder!`,
+ );
+}
+
+export default class TestAdapter extends BasicAdapter {
+ constructor() {
+ super(...arguments);
+ adapter = this;
+ }
+
+ get name() {
+ return 'test';
+ }
+
+ get canOpenResource() {
+ return resourcesEnabled;
+ }
+
+ openResource(file, line) {
+ if (!resourcesEnabled) {
+ throw new Error('openResource called unexpectedly');
+ }
+
+ console.debug('Opening resource', { file, line });
+
+ if (!file) {
+ QUnit.assert.ok(
+ file,
+ `resource has valid "file" field: ${JSON.stringify(file)}`,
+ );
+ return;
+ }
+
+ if (!line) {
+ QUnit.assert.ok(
+ file,
+ `resource has valid "line" field: ${JSON.stringify(line)}`,
+ );
+ return;
+ }
+
+ for (let resource of resources) {
+ let { actual, expected, resolve } = resource;
+
+ if (actual === expected) {
+ continue;
+ }
+
+ if (file === resource.file && line === resource.line) {
+ console.debug('Opened resource', { file, line });
+ resource.actual = ++actual;
+ resolve();
+ return;
+ }
+ }
+
+ console.error('Unknown resource', { file, line });
+
+ QUnit.assert.deepEqual({ file, line }, {}, 'Unknown resource');
+ }
+
+ sendMessage(message) {
+ console.debug('Sending message (devtools -> inspectedWindow)', message);
+
+ if (!message.type) {
+ QUnit.assert.ok(
+ false,
+ `message has valid "type" field: ${JSON.stringify(message)}`,
+ );
+ return;
+ }
+
+ if (message.from !== 'devtools') {
+ QUnit.assert.strictEqual(
+ message.from,
+ 'devtools',
+ `message has valid "from" field: ${JSON.stringify(message)}`,
+ );
+ return;
+ }
+
+ for (let responder of responders) {
+ let { type, callback, actual, expected, resolve } = responder;
+
+ if (actual === expected) {
+ continue;
+ }
+
+ if (type === message.type) {
+ let response = callback(message);
+
+ if (response !== undefined) {
+ responder.actual = ++actual;
+ }
+
+ let didRespond;
+
+ if (response) {
+ console.debug(
+ 'Received response (inspectedWindow -> devtools)',
+ response,
+ );
+ didRespond = sendMessage(response);
+ } else if (response === false) {
+ console.debug(
+ 'Ignoreing message (devtools -> inspectedWindow)',
+ message,
+ );
+ didRespond = Promise.resolve();
+ }
+
+ if (didRespond) {
+ if (actual === expected) {
+ didRespond.then(resolve);
+ }
+
+ return;
+ }
+ }
+ }
+
+ console.error('Unexpected message', message);
+
+ QUnit.assert.deepEqual(message, {}, 'Unexpected message');
+ }
+}
diff --git a/test-apps/tests/test-helper.js b/test-apps/tests/test-helper.js
new file mode 100644
index 0000000000..b278026a1e
--- /dev/null
+++ b/test-apps/tests/test-helper.js
@@ -0,0 +1,31 @@
+import Application from 'test-app/app';
+import config from 'test-app/config/environment';
+import * as QUnit from 'qunit';
+import { setApplication } from '@ember/test-helpers';
+import { setup } from 'qunit-dom';
+import { start } from 'ember-qunit';
+import TestAdapter from './test-adapter';
+import setupSinon from 'ember-sinon-qunit';
+
+/**
+ * we need to override the adapter that is set up in initializers/setup.js
+ * for that we suffix the name of setup initializer with `-2` so that
+ * this initializer comes right after it
+ */
+Application.initializer({
+ name: `setup-2-override-adapter`,
+ initialize(app) {
+ app.register('service:adapter', TestAdapter);
+ },
+});
+
+setApplication(Application.create(config.APP));
+
+setupSinon();
+
+window.NO_EMBER_DEBUG = true;
+QUnit.config.testTimeout = 60000;
+
+setup(QUnit.assert);
+
+start();
diff --git a/test-apps/tests/unit/.gitkeep b/test-apps/tests/unit/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/unit/utils/type-check-test.js b/test-apps/tests/unit/utils/type-check-test.js
similarity index 100%
rename from tests/unit/utils/type-check-test.js
rename to test-apps/tests/unit/utils/type-check-test.js
diff --git a/tests/index.html b/tests/index.html
index 07b1a904a3..6fe4ea4efb 100644
--- a/tests/index.html
+++ b/tests/index.html
@@ -26,7 +26,6 @@
-
{{content-for "head-footer"}}
{{content-for "test-head-footer"}}
diff --git a/tsconfig.json b/tsconfig.json
index 1c159c047d..32ce044bec 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -19,5 +19,5 @@
},
"types": ["chrome", "./node_modules/ember-source/types/stable"]
},
- "include": ["app/**/*", "tests/**/*", "types/**/*", "lib/ui/**/*"]
+ "include": ["app/**/*", "test-apps/**/*", "tests/**/*", "types/**/*", "lib/ui/**/*"]
}