ember-exam 9.0.0 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/.release-plan.json +30 -0
  2. package/README.md +65 -2
  3. package/addon-test-support/-private/async-iterator.js +0 -1
  4. package/addon-test-support/-private/ember-exam-test-loader.js +63 -5
  5. package/addon-test-support/index.js +1 -0
  6. package/addon-test-support/load.js +0 -1
  7. package/addon-test-support/start.js +8 -5
  8. package/docs-app/.vitepress/config.mts +54 -0
  9. package/docs-app/.vitepress/theme/index.ts +17 -0
  10. package/docs-app/.vitepress/theme/style.css +170 -0
  11. package/docs-app/ember-try-and-ci.md +38 -0
  12. package/docs-app/filtering.md +47 -0
  13. package/docs-app/index.md +46 -0
  14. package/docs-app/load-balancing.md +96 -0
  15. package/docs-app/module-metadata.md +48 -0
  16. package/docs-app/package.json +26 -0
  17. package/docs-app/preserve-test-name.md +26 -0
  18. package/docs-app/quickstart.md +128 -0
  19. package/docs-app/randomization-iterator.md +22 -0
  20. package/docs-app/randomization.md +29 -0
  21. package/docs-app/split-parallel.md +33 -0
  22. package/docs-app/splitting.md +19 -0
  23. package/docs-app/test-suite-segmentation.md +14 -0
  24. package/docs-app/tsconfig.json +23 -0
  25. package/lib/commands/exam/iterate.js +1 -1
  26. package/lib/commands/exam.js +1 -1
  27. package/lib/commands/task/test-server.js +0 -1
  28. package/lib/commands/task/test.js +9 -1
  29. package/lib/utils/config-reader.js +4 -1
  30. package/lib/utils/test-page-helper.js +0 -1
  31. package/lib/utils/tests-options-validator.js +0 -1
  32. package/package.json +40 -75
  33. package/pnpm-workspace.yaml +76 -0
  34. package/test-apps/broccoli/.editorconfig +19 -0
  35. package/test-apps/broccoli/.ember-cli +7 -0
  36. package/test-apps/broccoli/.github/workflows/ci.yml +47 -0
  37. package/test-apps/broccoli/.prettierignore +13 -0
  38. package/test-apps/broccoli/.prettierrc.js +12 -0
  39. package/test-apps/broccoli/.stylelintignore +8 -0
  40. package/test-apps/broccoli/.stylelintrc.js +5 -0
  41. package/test-apps/broccoli/.template-lintrc.js +5 -0
  42. package/test-apps/broccoli/.watchmanconfig +3 -0
  43. package/test-apps/broccoli/README.md +56 -0
  44. package/test-apps/broccoli/app/app.js +12 -0
  45. package/test-apps/broccoli/app/index.html +24 -0
  46. package/test-apps/broccoli/app/router.js +9 -0
  47. package/test-apps/broccoli/app/styles/app.css +1 -0
  48. package/test-apps/broccoli/app/templates/application.hbs +7 -0
  49. package/test-apps/broccoli/config/ember-cli-update.json +20 -0
  50. package/test-apps/broccoli/config/environment.js +48 -0
  51. package/test-apps/broccoli/config/optional-features.json +7 -0
  52. package/test-apps/broccoli/config/targets.js +11 -0
  53. package/test-apps/broccoli/ember-cli-build.js +11 -0
  54. package/test-apps/broccoli/package.json +71 -0
  55. package/test-apps/broccoli/public/robots.txt +3 -0
  56. package/test-apps/broccoli/testem.js +23 -0
  57. package/test-apps/broccoli/tests/index.html +39 -0
  58. package/test-apps/broccoli/tests/test-helper.js +12 -0
  59. package/test-apps/embroider3-webpack/.editorconfig +19 -0
  60. package/test-apps/embroider3-webpack/.ember-cli +19 -0
  61. package/test-apps/embroider3-webpack/.github/workflows/ci.yml +47 -0
  62. package/test-apps/embroider3-webpack/.prettierignore +13 -0
  63. package/test-apps/embroider3-webpack/.prettierrc.js +14 -0
  64. package/test-apps/embroider3-webpack/.stylelintignore +5 -0
  65. package/test-apps/embroider3-webpack/.stylelintrc.js +5 -0
  66. package/test-apps/embroider3-webpack/.template-lintrc.js +5 -0
  67. package/test-apps/embroider3-webpack/.watchmanconfig +3 -0
  68. package/test-apps/embroider3-webpack/README.md +56 -0
  69. package/test-apps/embroider3-webpack/app/app.js +17 -0
  70. package/test-apps/embroider3-webpack/app/deprecation-workflow.js +24 -0
  71. package/test-apps/embroider3-webpack/app/index.html +24 -0
  72. package/test-apps/embroider3-webpack/app/router.js +9 -0
  73. package/test-apps/embroider3-webpack/app/styles/app.css +1 -0
  74. package/test-apps/embroider3-webpack/app/templates/application.hbs +7 -0
  75. package/test-apps/embroider3-webpack/config/ember-cli-update.json +21 -0
  76. package/test-apps/embroider3-webpack/config/environment.js +48 -0
  77. package/test-apps/embroider3-webpack/config/optional-features.json +7 -0
  78. package/test-apps/embroider3-webpack/config/targets.js +11 -0
  79. package/test-apps/embroider3-webpack/ember-cli-build.js +31 -0
  80. package/test-apps/embroider3-webpack/package.json +74 -0
  81. package/test-apps/embroider3-webpack/public/robots.txt +3 -0
  82. package/test-apps/embroider3-webpack/testem.js +23 -0
  83. package/test-apps/embroider3-webpack/tests/index.html +39 -0
  84. package/test-apps/embroider3-webpack/tests/test-helper.js +9 -0
  85. package/test-apps/vite-with-compat/.editorconfig +19 -0
  86. package/test-apps/vite-with-compat/.ember-cli +19 -0
  87. package/test-apps/vite-with-compat/.env.development +8 -0
  88. package/test-apps/vite-with-compat/.env.test +8 -0
  89. package/test-apps/vite-with-compat/.prettierignore +13 -0
  90. package/test-apps/vite-with-compat/.prettierrc.mjs +37 -0
  91. package/test-apps/vite-with-compat/.template-lintrc.mjs +3 -0
  92. package/test-apps/vite-with-compat/.watchmanconfig +3 -0
  93. package/test-apps/vite-with-compat/README.md +57 -0
  94. package/test-apps/vite-with-compat/app/app.js +10 -0
  95. package/test-apps/vite-with-compat/app/config/environment.js +27 -0
  96. package/test-apps/vite-with-compat/app/router.js +9 -0
  97. package/test-apps/vite-with-compat/babel.config.cjs +42 -0
  98. package/test-apps/vite-with-compat/config/ember-cli-update.json +19 -0
  99. package/test-apps/vite-with-compat/config/environment.js +48 -0
  100. package/test-apps/vite-with-compat/config/optional-features.json +7 -0
  101. package/test-apps/vite-with-compat/config/targets.js +11 -0
  102. package/test-apps/vite-with-compat/ember-cli-build.js +22 -0
  103. package/test-apps/vite-with-compat/index.html +9 -0
  104. package/test-apps/vite-with-compat/package.json +81 -0
  105. package/test-apps/vite-with-compat/public/robots.txt +3 -0
  106. package/test-apps/vite-with-compat/testem.cjs +27 -0
  107. package/test-apps/vite-with-compat/tests/index.html +46 -0
  108. package/test-apps/vite-with-compat/tests/integration/a-test.gjs +28 -0
  109. package/test-apps/vite-with-compat/tests/integration/b-test.gjs +28 -0
  110. package/test-apps/vite-with-compat/tests/test-helper.js +14 -0
  111. package/test-apps/vite-with-compat/vite.config.mjs +59 -0
  112. package/.codeclimate.yml +0 -20
  113. package/addon-test-support/.eslintrc +0 -6
  114. package/lib/.eslintrc +0 -5
@@ -0,0 +1,30 @@
1
+ {
2
+ "solution": {
3
+ "ember-exam": {
4
+ "impact": "major",
5
+ "oldVersion": "9.1.0",
6
+ "newVersion": "10.0.0",
7
+ "tagName": "latest",
8
+ "constraints": [
9
+ {
10
+ "impact": "major",
11
+ "reason": "Appears in changelog section :boom: Breaking Change"
12
+ },
13
+ {
14
+ "impact": "patch",
15
+ "reason": "Appears in changelog section :bug: Bug Fix"
16
+ },
17
+ {
18
+ "impact": "patch",
19
+ "reason": "Appears in changelog section :memo: Documentation"
20
+ },
21
+ {
22
+ "impact": "patch",
23
+ "reason": "Appears in changelog section :house: Internal"
24
+ }
25
+ ],
26
+ "pkgJSONPath": "./package.json"
27
+ }
28
+ },
29
+ "description": "## Release (2025-08-26)\n\n* ember-exam 10.0.0 (major)\n\n#### :boom: Breaking Change\n* `ember-exam`\n * [#1430](https://github.com/ember-cli/ember-exam/pull/1430) Support vite ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n\n#### :bug: Bug Fix\n* `ember-exam`\n * [#1450](https://github.com/ember-cli/ember-exam/pull/1450) Support cjs testem configs ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n\n#### :memo: Documentation\n* `ember-exam`\n * [#1347](https://github.com/ember-cli/ember-exam/pull/1347) Update setup example for new qunit requirements ([@elwayman02](https://github.com/elwayman02))\n\n#### :house: Internal\n* `ember-exam`\n * [#1449](https://github.com/ember-cli/ember-exam/pull/1449) Spit node-tests in to parallel jobs for easier retries (we have a very short testem timeout) ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n * [#1451](https://github.com/ember-cli/ember-exam/pull/1451) Delete test duplication and use symlinks instead ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n * [#1452](https://github.com/ember-cli/ember-exam/pull/1452) Remove extraneous command in CI workflow ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n * [#1448](https://github.com/ember-cli/ember-exam/pull/1448) Split out try scenarios in to real apps for easier debugging ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n * [#1443](https://github.com/ember-cli/ember-exam/pull/1443) Remove unused deps ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n * [#1442](https://github.com/ember-cli/ember-exam/pull/1442) Get rid of custom resolver form an older era of the blueprint ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n * [#1439](https://github.com/ember-cli/ember-exam/pull/1439) Update renovate-config (move to weekly) ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n * [#1441](https://github.com/ember-cli/ember-exam/pull/1441) Set base for pages deployment ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n * [#1440](https://github.com/ember-cli/ember-exam/pull/1440) Fix static files path for gh-pages deploy ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n * [#1435](https://github.com/ember-cli/ember-exam/pull/1435) Strict dep management settings + re-roll lockfile, remove addon-docs, add vitepress ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n * [#1434](https://github.com/ember-cli/ember-exam/pull/1434) Add prettier to lint, don't run lint with tests ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n * [#1431](https://github.com/ember-cli/ember-exam/pull/1431) Upgrade eslint / prettier ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n\n#### Committers: 2\n- Jordan Hawker ([@elwayman02](https://github.com/elwayman02))\n- [@NullVoxPopuli](https://github.com/NullVoxPopuli)\n"
30
+ }
package/README.md CHANGED
@@ -39,7 +39,7 @@ The [documentation website](https://ember-cli.github.io/ember-exam/) contains ex
39
39
  Installation is as easy as running:
40
40
 
41
41
  ```bash
42
- $ ember install ember-exam
42
+ $ npm install --save-dev ember-exam
43
43
  ```
44
44
 
45
45
  ## How To Use
@@ -72,12 +72,75 @@ To get the unique features of Ember Exam (described in-depth below), you will ne
72
72
 
73
73
  ```js
74
74
  // test-helper.js
75
- import start from 'ember-exam/test-support/start';
75
+ - import { start, setupEmberOnerrorValidation } from 'ember-qunit';
76
+ + import { setupEmberOnerrorValidation } from 'ember-qunit';
77
+ + import { start } from 'ember-exam/test-support';
76
78
 
77
79
  // Options passed to `start` will be passed-through to ember-qunit
78
80
  start();
79
81
  ```
80
82
 
83
+ ## How to use with Vite
84
+
85
+ All of the above applies, but we need to tell vite to build the app before telling ember/exam to run tests on that output.
86
+
87
+ Update your test-helper.js or test-helper.ts, to have add the ember-exam `start` function:
88
+ ```diff
89
+ // ...
90
+ import { setApplication } from '@ember/test-helpers';
91
+ import { setup } from 'qunit-dom';
92
+ - import { start as qunitStart, setupEmberOnerrorValidation } from 'ember-qunit';
93
+ + import { setupEmberOnerrorValidation } from 'ember-qunit';
94
+ + import { start as startEmberExam } from 'ember-exam/test-support';
95
+
96
+ - export function start() {
97
+ + export async function start({ availableModules }) {
98
+ setApplication(Application.create(config.APP));
99
+
100
+ setup(QUnit.assert);
101
+ setupEmberOnerrorValidation();
102
+
103
+ - qunitStart();
104
+ + // Options passed to `start` will be passed-through to ember-qunit
105
+ + await startEmberExam({ availableModules });
106
+ }
107
+ ```
108
+
109
+ Then, update your tests/index.html to pass availableModules to start:
110
+ ```html
111
+ <script type="module">
112
+ import { start } from './test-helper.js';
113
+
114
+ const availableModules = {
115
+ ...import.meta.glob('./application/**/*-test.{js,ts,gjs,gts}'),
116
+ ...import.meta.glob('./rendering/**/*-test.{js,ts,gjs,gts}'),
117
+ ...import.meta.glob('./unit/**/*-test.{js,ts,gjs,gts}'),
118
+ };
119
+
120
+ start({ availableModules });
121
+ </script>
122
+ ```
123
+
124
+
125
+ Testing development:
126
+ ```bash
127
+ NODE_ENV=development vite build --mode development
128
+ ember exam --path dist --config-file ./testem.cjs
129
+ ```
130
+
131
+ Testing production:
132
+ ```bash
133
+ vite build --mode test
134
+ ember exam --path dist --config-file ./testem.cjs
135
+ ```
136
+
137
+ > [!NOTE]
138
+ > Specifying the `--path` is important because otherwise ember-cli will try to build your vite app, and it will error.
139
+
140
+ > [!NOTE]
141
+ > Specifying the `--config-path` is important because ember-cli (what backs ember-exam) doesn't know about cjs files.
142
+
143
+
81
144
  ### Version < `3.0.0`
82
145
 
83
146
 
@@ -115,7 +115,6 @@ export default class AsyncIterator {
115
115
  );
116
116
  reject(err);
117
117
  } else {
118
- // eslint-disable-next-line no-console
119
118
  console.error(
120
119
  `EmberExam: Promise timed out after ${this._timeout} s while waiting for response for ${this._request}. Closing browser to exit gracefully.`,
121
120
  );
@@ -1,3 +1,4 @@
1
+ import { assert } from '@ember/debug';
1
2
  import getUrlParams from './get-url-params';
2
3
  import splitTestModules from './split-test-modules';
3
4
  import weightTestModules from './weight-test-modules';
@@ -59,7 +60,7 @@ export default class EmberExamTestLoader extends TestLoader {
59
60
  *
60
61
  * @method loadModules
61
62
  */
62
- loadModules() {
63
+ async loadModules({ availableModules } = {}) {
63
64
  const loadBalance = this._urlParams.get('loadBalance');
64
65
  const browserId = this._urlParams.get('browser');
65
66
  const modulePath = this._urlParams.get('modulePath');
@@ -75,7 +76,18 @@ export default class EmberExamTestLoader extends TestLoader {
75
76
  partitions = [partitions];
76
77
  }
77
78
 
78
- super.loadModules();
79
+ if (!availableModules) {
80
+ super.loadModules();
81
+ } else {
82
+ assert(
83
+ `Available modules must be an object.`,
84
+ typeof availableModules === 'object',
85
+ );
86
+
87
+ this._availableModules = availableModules;
88
+ this._testModules = Object.keys(availableModules);
89
+ }
90
+
79
91
  this.setupModuleMetadataHandler();
80
92
 
81
93
  if (modulePath || filePath) {
@@ -93,6 +105,7 @@ export default class EmberExamTestLoader extends TestLoader {
93
105
  split,
94
106
  partitions,
95
107
  );
108
+
96
109
  this._testem.emit(
97
110
  'testem:set-modules-queue',
98
111
  this._testModules,
@@ -104,6 +117,15 @@ export default class EmberExamTestLoader extends TestLoader {
104
117
  split,
105
118
  partitions,
106
119
  );
120
+
121
+ if (this._availableModules) {
122
+ await this.loadAvailableModules();
123
+ return;
124
+ }
125
+
126
+ /**
127
+ * Legacy support
128
+ */
107
129
  this._testModules.forEach((moduleName) => {
108
130
  super.require(moduleName);
109
131
  super.unsee(moduleName);
@@ -111,18 +133,54 @@ export default class EmberExamTestLoader extends TestLoader {
111
133
  }
112
134
  }
113
135
 
136
+ /**
137
+ * availableModules are passed in from loadModules
138
+ * from loadEmberExam
139
+ * from start
140
+ */
141
+ async loadAvailableModules() {
142
+ if (this._availableModules) {
143
+ await Promise.all(
144
+ this._testModules.map(async (moduleName) => {
145
+ let loader = this._availableModules[moduleName];
146
+
147
+ /**
148
+ * If it's not a function, it's already loaded
149
+ */
150
+ if (typeof loader === 'function') {
151
+ await loader();
152
+ }
153
+ }),
154
+ );
155
+ }
156
+ }
157
+
114
158
  /**
115
159
  * Allow loading one module at a time.
116
160
  *
117
161
  * @method loadIndividualModule
118
162
  * @param {string} moduleName
119
163
  */
120
- loadIndividualModule(moduleName) {
164
+ async loadIndividualModule(moduleName) {
121
165
  if (moduleName === undefined) {
122
166
  throw new Error(
123
167
  'Failed to load a test module. `moduleName` is undefined in `loadIndividualModule`.',
124
168
  );
125
169
  }
170
+
171
+ if (this._availableModules) {
172
+ let loader = this._availableModules[moduleName];
173
+
174
+ /**
175
+ * If it's not a function, it's already loaded
176
+ */
177
+ if (typeof loader === 'function') {
178
+ await loader();
179
+ }
180
+
181
+ return;
182
+ }
183
+
126
184
  super.require(moduleName);
127
185
  super.unsee(moduleName);
128
186
  }
@@ -168,10 +226,10 @@ export default class EmberExamTestLoader extends TestLoader {
168
226
 
169
227
  return nextModuleAsyncIterator
170
228
  .next()
171
- .then((response) => {
229
+ .then(async (response) => {
172
230
  if (!response.done) {
173
231
  const moduleName = response.value;
174
- this.loadIndividualModule(moduleName);
232
+ await this.loadIndividualModule(moduleName);
175
233
 
176
234
  // if no tests were added, request the next module
177
235
  if (this._qunit.config.queue.length === 0) {
@@ -0,0 +1 @@
1
+ export { default as start } from './start';
@@ -11,7 +11,6 @@ let loaded = false;
11
11
  */
12
12
  export default function loadEmberExam() {
13
13
  if (loaded) {
14
- // eslint-disable-next-line no-console
15
14
  console.warn('Attempted to load Ember Exam more than once.');
16
15
  return;
17
16
  }
@@ -6,15 +6,16 @@ import { start as qunitStart } from 'ember-qunit';
6
6
  *
7
7
  * @function loadTests
8
8
  * @param {*} testLoader
9
+ * @param {*} loaderOptions
9
10
  */
10
- function loadTests(testLoader) {
11
+ async function loadTests(testLoader, loaderOptions = {}) {
11
12
  if (testLoader === undefined) {
12
13
  throw new Error(
13
14
  'A testLoader instance has not been created. You must call `loadEmberExam()` before calling `loadTest()`.',
14
15
  );
15
16
  }
16
17
 
17
- testLoader.loadModules();
18
+ await testLoader.loadModules(loaderOptions);
18
19
  }
19
20
 
20
21
  /**
@@ -24,11 +25,13 @@ function loadTests(testLoader) {
24
25
  * @function start
25
26
  * @param {*} qunitOptions
26
27
  */
27
- export default function start(qunitOptions) {
28
- const modifiedOptions = qunitOptions || Object.create(null);
28
+ export default async function start(qunitOptions = {}) {
29
+ const { availableModules, ...modifiedOptions } =
30
+ qunitOptions || Object.create(null);
31
+
29
32
  modifiedOptions.loadTests = false;
30
33
 
31
34
  const testLoader = loadEmberExam();
32
- loadTests(testLoader);
35
+ await loadTests(testLoader, { availableModules });
33
36
  qunitStart(modifiedOptions);
34
37
  }
@@ -0,0 +1,54 @@
1
+ import { defineConfig } from 'vitepress'
2
+
3
+ // https://vitepress.dev/reference/site-config
4
+ export default defineConfig({
5
+ title: "ember-exam",
6
+ description: "Run your tests with randomization, splitting, and parallelization for beautiful tests.",
7
+ base: '/ember-exam/',
8
+ markdown: {
9
+ // theme: {
10
+ // ...dark,
11
+ // settings: [
12
+ // {
13
+ // scope: 'comment',
14
+ // settings: {
15
+ // // 'foreground': 'rgb(200, 200, 200)'
16
+ // }
17
+ // },
18
+ // ]
19
+ // },
20
+ },
21
+ themeConfig: {
22
+ // https://vitepress.dev/reference/default-theme-config
23
+ nav: [
24
+ { text: 'Home', link: '/' },
25
+ // { text: 'Examples', link: '/markdown-examples' }
26
+ ],
27
+
28
+ sidebar: [
29
+ {
30
+ text: 'Options',
31
+ items: [
32
+ { text: 'Randomization', link: '/randomization' },
33
+ { text: 'Randomization Iterator', link: '/randomization-iterator' },
34
+ { text: 'Generating Module Metadata For Test Execution', link: '/module-metadata' },
35
+ { text: 'Splitting', link: '/splitting' },
36
+ { text: 'Split Test Parallelization', link: '/split-parallel' },
37
+ { text: 'Filtering', link: '/filtering' },
38
+ { text: 'Test Load Balancing', link: '/load-balancing' },
39
+ ]
40
+ },
41
+ {
42
+ text: 'Advanced Configuration',
43
+ items: [
44
+ { text: 'Ember Try & CI Integration', link: '/ember-try-and-ci' },
45
+ { text: 'Test Suite Segmentation', link: '/test-suite-segmentation' },
46
+ ]
47
+ }
48
+ ],
49
+
50
+ socialLinks: [
51
+ { icon: 'github', link: 'https://github.com/ember-cli/ember-exam' }
52
+ ]
53
+ }
54
+ })
@@ -0,0 +1,17 @@
1
+ // https://vitepress.dev/guide/custom-theme
2
+ import { h } from 'vue'
3
+ import type { Theme } from 'vitepress'
4
+ import DefaultTheme from 'vitepress/theme'
5
+ import './style.css'
6
+
7
+ export default {
8
+ extends: DefaultTheme,
9
+ Layout: () => {
10
+ return h(DefaultTheme.Layout, null, {
11
+ // https://vitepress.dev/guide/extending-default-theme#layout-slots
12
+ })
13
+ },
14
+ enhanceApp({ app, router, siteData }) {
15
+ // ...
16
+ }
17
+ } satisfies Theme
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Customize default theme styling by overriding CSS variables:
3
+ * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
4
+ */
5
+
6
+ /**
7
+ * Colors
8
+ *
9
+ * Each colors have exact same color scale system with 3 levels of solid
10
+ * colors with different brightness, and 1 soft color.
11
+ *
12
+ * - `XXX-1`: The most solid color used mainly for colored text. It must
13
+ * satisfy the contrast ratio against when used on top of `XXX-soft`.
14
+ *
15
+ * - `XXX-2`: The color used mainly for hover state of the button.
16
+ *
17
+ * - `XXX-3`: The color for solid background, such as bg color of the button.
18
+ * It must satisfy the contrast ratio with pure white (#ffffff) text on
19
+ * top of it.
20
+ *
21
+ * - `XXX-soft`: The color used for subtle background such as custom container
22
+ * or badges. It must satisfy the contrast ratio when putting `XXX-1` colors
23
+ * on top of it.
24
+ *
25
+ * The soft color must be semi transparent alpha channel. This is crucial
26
+ * because it allows adding multiple "soft" colors on top of each other
27
+ * to create a accent, such as when having inline code block inside
28
+ * custom containers.
29
+ *
30
+ * - `default`: The color used purely for subtle indication without any
31
+ * special meanings attached to it such as bg color for menu hover state.
32
+ *
33
+ * - `brand`: Used for primary brand colors, such as link text, button with
34
+ * brand theme, etc.
35
+ *
36
+ * - `tip`: Used to indicate useful information. The default theme uses the
37
+ * brand color for this by default.
38
+ *
39
+ * - `warning`: Used to indicate warning to the users. Used in custom
40
+ * container, badges, etc.
41
+ *
42
+ * - `danger`: Used to show error, or dangerous message to the users. Used
43
+ * in custom container, badges, etc.
44
+ * -------------------------------------------------------------------------- */
45
+
46
+ :root {
47
+ --vp-c-default-1: var(--vp-c-gray-1);
48
+ --vp-c-default-2: var(--vp-c-gray-2);
49
+ --vp-c-default-3: var(--vp-c-gray-3);
50
+ --vp-c-default-soft: var(--vp-c-gray-soft);
51
+
52
+ --vp-c-brand-1: var(--vp-c-indigo-1);
53
+ --vp-c-brand-2: var(--vp-c-indigo-2);
54
+ --vp-c-brand-3: var(--vp-c-indigo-3);
55
+ --vp-c-brand-soft: var(--vp-c-indigo-soft);
56
+
57
+ --vp-c-tip-1: var(--vp-c-brand-1);
58
+ --vp-c-tip-2: var(--vp-c-brand-2);
59
+ --vp-c-tip-3: var(--vp-c-brand-3);
60
+ --vp-c-tip-soft: var(--vp-c-brand-soft);
61
+
62
+ --vp-c-warning-1: var(--vp-c-yellow-1);
63
+ --vp-c-warning-2: var(--vp-c-yellow-2);
64
+ --vp-c-warning-3: var(--vp-c-yellow-3);
65
+ --vp-c-warning-soft: var(--vp-c-yellow-soft);
66
+
67
+ --vp-c-danger-1: var(--vp-c-red-1);
68
+ --vp-c-danger-2: var(--vp-c-red-2);
69
+ --vp-c-danger-3: var(--vp-c-red-3);
70
+ --vp-c-danger-soft: var(--vp-c-red-soft);
71
+ }
72
+
73
+ /**
74
+ * Component: Button
75
+ * -------------------------------------------------------------------------- */
76
+
77
+ :root {
78
+ --vp-button-brand-border: transparent;
79
+ --vp-button-brand-text: var(--vp-c-white);
80
+ --vp-button-brand-bg: var(--vp-c-brand-3);
81
+ --vp-button-brand-hover-border: transparent;
82
+ --vp-button-brand-hover-text: var(--vp-c-white);
83
+ --vp-button-brand-hover-bg: var(--vp-c-brand-2);
84
+ --vp-button-brand-active-border: transparent;
85
+ --vp-button-brand-active-text: var(--vp-c-white);
86
+ --vp-button-brand-active-bg: var(--vp-c-brand-1);
87
+ }
88
+
89
+ /**
90
+ * Component: Home
91
+ * -------------------------------------------------------------------------- */
92
+
93
+ :root {
94
+ --vp-home-hero-name-color: transparent;
95
+ --vp-home-hero-name-background: -webkit-linear-gradient(
96
+ 120deg,
97
+ #bd34fe 30%,
98
+ #41d1ff
99
+ );
100
+
101
+ --vp-home-hero-image-background-image: linear-gradient(
102
+ -45deg,
103
+ #bd34fe 50%,
104
+ #47caff 50%
105
+ );
106
+ --vp-home-hero-image-filter: blur(44px);
107
+ }
108
+
109
+ @media (min-width: 640px) {
110
+ :root {
111
+ --vp-home-hero-image-filter: blur(56px);
112
+ }
113
+ }
114
+
115
+ @media (min-width: 960px) {
116
+ :root {
117
+ --vp-home-hero-image-filter: blur(68px);
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Component: Custom Block
123
+ * -------------------------------------------------------------------------- */
124
+
125
+ :root {
126
+ --vp-custom-block-tip-border: transparent;
127
+ --vp-custom-block-tip-text: var(--vp-c-text-1);
128
+ --vp-custom-block-tip-bg: var(--vp-c-brand-soft);
129
+ --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
130
+ }
131
+
132
+ /**
133
+ * Component: Algolia
134
+ * -------------------------------------------------------------------------- */
135
+
136
+ .DocSearch {
137
+ --docsearch-primary-color: var(--vp-c-brand-1) !important;
138
+ }
139
+
140
+
141
+
142
+ .badges {
143
+ > p {
144
+ display: flex;
145
+ gap: 1rem;
146
+ justify-content: center;
147
+ align-items: center;
148
+ }
149
+ img, a {
150
+ display: inline-flex;
151
+ }
152
+
153
+ }
154
+
155
+ /**
156
+ * Contrast fixes
157
+ */
158
+ html {
159
+ --vp-c-text-2: rgb(40, 40, 40);
160
+ }
161
+ html.dark {
162
+ --vp-c-text-2: rgb(200, 200, 200);
163
+ }
164
+
165
+ html [class*='language-'] > span.lang {
166
+ --vp-code-lang-color: rgb(40,40,40);
167
+ }
168
+ html.dark [class*='language-'] > span.lang {
169
+ --vp-code-lang-color: rgb(200,200,200);
170
+ }
@@ -0,0 +1,38 @@
1
+ ### Ember Try & CI Integration
2
+
3
+ Integrating ember-exam with [ember-try](https://github.com/ember-cli/ember-try) is remarkably easy. Define a [`command` in your `ember-try.js` config](https://github.com/ember-cli/ember-try#configuration-files) that leverages the `exam` command:
4
+
5
+ ```js
6
+ // config/ember-try.js
7
+ module.exports = {
8
+ command: 'ember exam --split 3 --parallel',
9
+ // ...
10
+ };
11
+ ```
12
+
13
+ Using [environmental variables](https://nodejs.org/api/process.html#process_process_env) gives you flexibility in how you run your tests. For instance, you could distribute your tests across processes instead of parallelizing them by specifying a `PARTITION` variable in your process environment and then consuming it like so:
14
+
15
+ ```js
16
+ module.exports = {
17
+ command: 'ember exam --split 20 --partition ' + process.env.PARTITION,
18
+ // ...
19
+ };
20
+ ```
21
+
22
+ If you are working with [Travis CI](https://travis-ci.org/) then you can also easily set up seeded-random runs based on PR numbers. Similar to the following:
23
+
24
+ ```js
25
+ const command = ['ember', 'exam', '--random'];
26
+ const pr = process.env.TRAVIS_PULL_REQUEST;
27
+
28
+ if (pr) {
29
+ command.push(pr);
30
+ }
31
+
32
+ module.exports = {
33
+ command: command.join(' '),
34
+ // ...
35
+ };
36
+ ```
37
+
38
+ You can refer to [Travis' default environment variables](https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables) to see what else you could possibly leverage for your test setup.
@@ -0,0 +1,47 @@
1
+ ### Filtering
2
+
3
+ Ember Exam provides options to filter test suites by two types - module path and test file path.
4
+
5
+ ```bash
6
+ $ ember exam --module-path=<module-path>
7
+ ```
8
+
9
+ #### For Vite Apps
10
+
11
+ The `file-path` option allows you to filter modules by the given relative path that is generated from `import.meta.glob(...)` in your `tests/index.html`.
12
+
13
+ ```bash
14
+ # This will run tests that are defined in `/my-application/tests/unit/my-test.js`
15
+ $ ember exam --file-path='/my-application/tests/unit/my-test.js'
16
+
17
+ # This will run all test files that are under `/my-application/tests/unit/`
18
+ $ ember exam --file-path='/my-application/tests/unit/*.js'
19
+ ```
20
+
21
+
22
+ #### For non-Vite Apps
23
+
24
+
25
+ The `module-path` option allows you to filter module paths by a given value. Module paths are mapped by test files and they are generated during `ember build`. After the build, `tests.js` file is created and it resides under [build-directory]/assets.
26
+
27
+ The file is combined of all tests in an application and it has a form of `define("<module-path>", others..`.
28
+
29
+ The value for `module-path` can have either string or regular expression, for instance:
30
+
31
+ ```bash
32
+ # When module path value is string. This will run all modules which match with the passed value
33
+ $ ember exam --module-path='dummy/tests/helpers/module-for-acceptance'
34
+
35
+ # When module path value is regex. This will run all modules which have `dummy` in it
36
+ $ ember exam --module-path='!/dummy/'
37
+ ```
38
+
39
+ The `file-path` option is to filter tests by *test file path*. The test file path is a location of the test file in a file system. You can specify `file-path` to a location of specific test file path or you can use wildcards in paths to target multiple test files.
40
+
41
+ ```bash
42
+ # This will run tests that are defined in `/my-application/tests/unit/my-test.js`
43
+ $ ember exam --file-path='/my-application/tests/unit/my-test.js'
44
+
45
+ # This will run all test files that are under `/my-application/tests/unit/`
46
+ $ ember exam --file-path='/my-application/tests/unit/*.js'
47
+ ```
@@ -0,0 +1,46 @@
1
+ ---
2
+ # https://vitepress.dev/reference/default-theme-home-page
3
+ layout: home
4
+
5
+ hero:
6
+ name: "ember-exam"
7
+ # text: "Run your tests with randomization, splitting, and parallelization for beautiful tests."
8
+ tagline: "Run your tests with randomization, splitting, and parallelization for beautiful tests."
9
+ actions:
10
+ - theme: brand
11
+ text: Quickstart
12
+ link: /quickstart
13
+ # - theme: alt
14
+ # text: API Examples
15
+ # link: /api-examples
16
+
17
+ features:
18
+ - title: Partitioning
19
+ details: Specify the number of parallel browser instances to use to speed up your test suite.
20
+ - title: Load Balancing
21
+ details: Balance tests to maximize the effectivess of parallel browsers that would otherwise completely quickly due to happenstance of being given quickly running tests.
22
+ - title: Randomization
23
+ details: Find and eliminate brittle tests by changing the order of tests within the test suite.
24
+ - title: Replay
25
+ details: Record and replay test execution order for reliably reproducing potentially flaky behaviors.
26
+ ---
27
+
28
+
29
+ <span class="badges">
30
+
31
+ ![Build Status](https://github.com/ember-cli/ember-exam/actions/workflows/ci.yml/badge.svg?event=push)
32
+ [![NPM Version](https://badge.fury.io/js/ember-exam.svg)][npm]
33
+ [![Ember Observer Score](https://emberobserver.com/badges/ember-exam.svg)][score]
34
+
35
+ </span>
36
+
37
+ [npm]: https://npmjs.com/package/ember-exam
38
+ [score]: https://emberobserver.com/addons/ember-exam
39
+
40
+ Ember Exam is an addon to allow you more control over how you run your tests when used in conjunction with [ember-qunit](https://github.com/emberjs/ember-qunit). It provides the ability to randomize, split, parallelize, and load-balance your test suite by adding a more robust CLI command.
41
+
42
+ It started as a way to help reduce flaky tests and encourage healthy test driven development.
43
+
44
+ [![Introduction to Ember Exam](https://cloud.githubusercontent.com/assets/2922250/22800360/157ad67c-eed7-11e6-8d33-d2c59238c7f1.png)](https://embermap.com/video/ember-exam)
45
+
46
+