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/**/*"] }