@fluidframework/test-utils 2.0.0-internal.3.0.2 → 2.0.0-internal.3.2.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 (65) hide show
  1. package/.eslintrc.js +8 -10
  2. package/README.md +41 -11
  3. package/api-extractor.json +2 -2
  4. package/dist/DriverWrappers.d.ts.map +1 -1
  5. package/dist/DriverWrappers.js.map +1 -1
  6. package/dist/TestConfigs.d.ts.map +1 -1
  7. package/dist/TestConfigs.js +3 -2
  8. package/dist/TestConfigs.js.map +1 -1
  9. package/dist/TestSummaryUtils.d.ts +15 -4
  10. package/dist/TestSummaryUtils.d.ts.map +1 -1
  11. package/dist/TestSummaryUtils.js +23 -17
  12. package/dist/TestSummaryUtils.js.map +1 -1
  13. package/dist/containerUtils.d.ts +1 -2
  14. package/dist/containerUtils.d.ts.map +1 -1
  15. package/dist/containerUtils.js +4 -2
  16. package/dist/containerUtils.js.map +1 -1
  17. package/dist/index.d.ts +4 -4
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/interfaces.d.ts.map +1 -1
  22. package/dist/interfaces.js.map +1 -1
  23. package/dist/loaderContainerTracker.d.ts.map +1 -1
  24. package/dist/loaderContainerTracker.js +37 -27
  25. package/dist/loaderContainerTracker.js.map +1 -1
  26. package/dist/localCodeLoader.d.ts.map +1 -1
  27. package/dist/localCodeLoader.js.map +1 -1
  28. package/dist/localLoader.d.ts.map +1 -1
  29. package/dist/localLoader.js.map +1 -1
  30. package/dist/packageVersion.d.ts +1 -1
  31. package/dist/packageVersion.js +1 -1
  32. package/dist/packageVersion.js.map +1 -1
  33. package/dist/retry.d.ts.map +1 -1
  34. package/dist/retry.js.map +1 -1
  35. package/dist/testContainerRuntimeFactory.d.ts.map +1 -1
  36. package/dist/testContainerRuntimeFactory.js +2 -1
  37. package/dist/testContainerRuntimeFactory.js.map +1 -1
  38. package/dist/testFluidObject.d.ts.map +1 -1
  39. package/dist/testFluidObject.js +7 -3
  40. package/dist/testFluidObject.js.map +1 -1
  41. package/dist/testObjectProvider.d.ts +4 -1
  42. package/dist/testObjectProvider.d.ts.map +1 -1
  43. package/dist/testObjectProvider.js +28 -11
  44. package/dist/testObjectProvider.js.map +1 -1
  45. package/dist/timeoutUtils.d.ts.map +1 -1
  46. package/dist/timeoutUtils.js +4 -3
  47. package/dist/timeoutUtils.js.map +1 -1
  48. package/package.json +66 -55
  49. package/prettier.config.cjs +1 -1
  50. package/src/DriverWrappers.ts +40 -37
  51. package/src/TestConfigs.ts +9 -7
  52. package/src/TestSummaryUtils.ts +113 -119
  53. package/src/containerUtils.ts +20 -18
  54. package/src/index.ts +24 -25
  55. package/src/interfaces.ts +10 -7
  56. package/src/loaderContainerTracker.ts +627 -565
  57. package/src/localCodeLoader.ts +85 -77
  58. package/src/localLoader.ts +24 -24
  59. package/src/packageVersion.ts +1 -1
  60. package/src/retry.ts +31 -25
  61. package/src/testContainerRuntimeFactory.ts +59 -56
  62. package/src/testFluidObject.ts +168 -152
  63. package/src/testObjectProvider.ts +445 -384
  64. package/src/timeoutUtils.ts +174 -154
  65. package/tsconfig.json +9 -16
@@ -16,185 +16,205 @@ export const defaultTimeoutDurationMs = 250;
16
16
  const timeBuffer = 15; // leave 15 ms leeway for finish processing
17
17
 
18
18
  class TestTimeout {
19
- private timeout: number = 0;
20
- private timer: NodeJS.Timeout | undefined;
21
- private readonly deferred: Deferred<void>;
22
- private rejected = false;
23
-
24
- private static instance: TestTimeout = new TestTimeout();
25
- public static reset(runnable: Mocha.Runnable) {
26
- TestTimeout.clear();
27
- TestTimeout.instance.resetTimer(runnable);
28
- }
29
-
30
- public static clear() {
31
- if (TestTimeout.instance.rejected) {
32
- TestTimeout.instance = new TestTimeout();
33
- } else {
34
- TestTimeout.instance.clearTimer();
35
- }
36
- }
37
-
38
- public static getInstance() {
39
- return TestTimeout.instance;
40
- }
41
-
42
- public async getPromise() {
43
- return this.deferred.promise;
44
- }
45
-
46
- public getTimeout() {
47
- return this.timeout;
48
- }
49
-
50
- private constructor() {
51
- this.deferred = new Deferred();
52
- // Ignore rejection for timeout promise if no one is waiting for it.
53
- this.deferred.promise.catch(() => { });
54
- }
55
-
56
- private resetTimer(runnable: Mocha.Runnable) {
57
- assert(!this.timer, "clearTimer should have been called before reset");
58
- assert(!this.deferred.isCompleted, "can't reset a completed TestTimeout");
59
-
60
- // Check the test timeout setting
61
- const timeout = runnable.timeout();
62
- if (!(Number.isFinite(timeout) && timeout > 0)) { return; }
63
-
64
- // subtract a buffer
65
- this.timeout = Math.max(timeout - timeBuffer, 1);
66
-
67
- // Set up timer to reject near the test timeout.
68
- this.timer = setTimeout(() => {
69
- this.deferred.reject(this);
70
- this.rejected = true;
71
- }, this.timeout);
72
- }
73
- private clearTimer() {
74
- if (this.timer) {
75
- clearTimeout(this.timer);
76
- this.timer = undefined;
77
- }
78
- }
19
+ private timeout: number = 0;
20
+ private timer: NodeJS.Timeout | undefined;
21
+ private readonly deferred: Deferred<void>;
22
+ private rejected = false;
23
+
24
+ private static instance: TestTimeout = new TestTimeout();
25
+ public static reset(runnable: Mocha.Runnable) {
26
+ TestTimeout.clear();
27
+ TestTimeout.instance.resetTimer(runnable);
28
+ }
29
+
30
+ public static clear() {
31
+ if (TestTimeout.instance.rejected) {
32
+ TestTimeout.instance = new TestTimeout();
33
+ } else {
34
+ TestTimeout.instance.clearTimer();
35
+ }
36
+ }
37
+
38
+ public static getInstance() {
39
+ return TestTimeout.instance;
40
+ }
41
+
42
+ public async getPromise() {
43
+ return this.deferred.promise;
44
+ }
45
+
46
+ public getTimeout() {
47
+ return this.timeout;
48
+ }
49
+
50
+ private constructor() {
51
+ this.deferred = new Deferred();
52
+ // Ignore rejection for timeout promise if no one is waiting for it.
53
+ this.deferred.promise.catch(() => {});
54
+ }
55
+
56
+ private resetTimer(runnable: Mocha.Runnable) {
57
+ assert(!this.timer, "clearTimer should have been called before reset");
58
+ assert(!this.deferred.isCompleted, "can't reset a completed TestTimeout");
59
+
60
+ // Check the test timeout setting
61
+ const timeout = runnable.timeout();
62
+ if (!(Number.isFinite(timeout) && timeout > 0)) {
63
+ return;
64
+ }
65
+
66
+ // subtract a buffer
67
+ this.timeout = Math.max(timeout - timeBuffer, 1);
68
+
69
+ // Set up timer to reject near the test timeout.
70
+ this.timer = setTimeout(() => {
71
+ this.deferred.reject(this);
72
+ this.rejected = true;
73
+ }, this.timeout);
74
+ }
75
+ private clearTimer() {
76
+ if (this.timer) {
77
+ clearTimeout(this.timer);
78
+ this.timer = undefined;
79
+ }
80
+ }
79
81
  }
80
82
 
81
83
  // only register if we are running with mocha-test-setup loaded
82
84
  if (globalThis.getMochaModule !== undefined) {
83
- // patching resetTimeout and clearTimeout on the runnable object
84
- // so we can track when test timeout are enforced
85
- const mochaModule = globalThis.getMochaModule() as typeof Mocha;
86
- const runnablePrototype = mochaModule.Runnable.prototype;
87
- // eslint-disable-next-line @typescript-eslint/unbound-method
88
- const oldResetTimeoutFunc = runnablePrototype.resetTimeout;
89
- runnablePrototype.resetTimeout = function(this: Mocha.Runnable) {
90
- oldResetTimeoutFunc.call(this);
91
- TestTimeout.reset(this);
92
- };
93
- // eslint-disable-next-line @typescript-eslint/unbound-method
94
- const oldClearTimeoutFunc = runnablePrototype.clearTimeout;
95
- runnablePrototype.clearTimeout = function(this: Mocha.Runnable) {
96
- TestTimeout.clear();
97
- oldClearTimeoutFunc.call(this);
98
- };
85
+ // patching resetTimeout and clearTimeout on the runnable object
86
+ // so we can track when test timeout are enforced
87
+ const mochaModule = globalThis.getMochaModule() as typeof Mocha;
88
+ const runnablePrototype = mochaModule.Runnable.prototype;
89
+ // eslint-disable-next-line @typescript-eslint/unbound-method
90
+ const oldResetTimeoutFunc = runnablePrototype.resetTimeout;
91
+ runnablePrototype.resetTimeout = function (this: Mocha.Runnable) {
92
+ oldResetTimeoutFunc.call(this);
93
+ TestTimeout.reset(this);
94
+ };
95
+ // eslint-disable-next-line @typescript-eslint/unbound-method
96
+ const oldClearTimeoutFunc = runnablePrototype.clearTimeout;
97
+ runnablePrototype.clearTimeout = function (this: Mocha.Runnable) {
98
+ TestTimeout.clear();
99
+ oldClearTimeoutFunc.call(this);
100
+ };
99
101
  }
100
102
 
101
103
  export interface TimeoutWithError {
102
- /**
103
- * Timeout duration in milliseconds, if it is great than 0 and not Infinity
104
- * If it is undefined, then it will use test timeout if we are in side the test function
105
- * Otherwise, there is no timeout
106
- */
107
- durationMs?: number;
108
- reject?: true;
109
- errorMsg?: string;
104
+ /**
105
+ * Timeout duration in milliseconds, if it is great than 0 and not Infinity
106
+ * If it is undefined, then it will use test timeout if we are in side the test function
107
+ * Otherwise, there is no timeout
108
+ */
109
+ durationMs?: number;
110
+ reject?: true;
111
+ errorMsg?: string;
110
112
  }
111
113
  export interface TimeoutWithValue<T = void> {
112
- /**
113
- * Timeout duration in milliseconds, if it is great than 0 and not Infinity
114
- * If it is undefined, then it will use test timeout if we are in side the test function
115
- * Otherwise, there is no timeout
116
- */
117
- durationMs?: number;
118
- reject: false;
119
- value: T;
114
+ /**
115
+ * Timeout duration in milliseconds, if it is great than 0 and not Infinity
116
+ * If it is undefined, then it will use test timeout if we are in side the test function
117
+ * Otherwise, there is no timeout
118
+ */
119
+ durationMs?: number;
120
+ reject: false;
121
+ value: T;
120
122
  }
121
123
 
122
- export type PromiseExecutor<T = void> = (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void;
124
+ export type PromiseExecutor<T = void> = (
125
+ resolve: (value: T | PromiseLike<T>) => void,
126
+ reject: (reason?: any) => void,
127
+ ) => void;
123
128
 
124
129
  export async function timeoutAwait<T = void>(
125
- promise: PromiseLike<T>,
126
- timeoutOptions: TimeoutWithError | TimeoutWithValue<T> = {},
130
+ promise: PromiseLike<T>,
131
+ timeoutOptions: TimeoutWithError | TimeoutWithValue<T> = {},
127
132
  ) {
128
- return Promise.race([promise, timeoutPromise<T>(() => { }, timeoutOptions)]);
133
+ return Promise.race([promise, timeoutPromise<T>(() => {}, timeoutOptions)]);
129
134
  }
130
135
 
131
136
  export async function ensureContainerConnected(container: Container): Promise<void> {
132
- if (!container.connected) {
133
- return timeoutPromise((resolve) => container.once("connected", () => resolve()));
134
- }
137
+ if (!container.connected) {
138
+ return timeoutPromise((resolve) => container.once("connected", () => resolve()));
139
+ }
135
140
  }
136
141
 
137
142
  // Create a promise based on the timeout options
138
143
  async function getTimeoutPromise<T = void>(
139
- executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void,
140
- timeoutOptions: TimeoutWithError | TimeoutWithValue<T>,
141
- err: Error | undefined,
144
+ executor: (
145
+ resolve: (value: T | PromiseLike<T>) => void,
146
+ reject: (reason?: any) => void,
147
+ ) => void,
148
+ timeoutOptions: TimeoutWithError | TimeoutWithValue<T>,
149
+ err: Error | undefined,
142
150
  ) {
143
- const timeout = timeoutOptions.durationMs ?? 0;
144
- if (timeout <= 0 || !Number.isFinite(timeout)) {
145
- return new Promise(executor);
146
- }
147
-
148
- return new Promise<T>((resolve, reject) => {
149
- const timeoutRejections = () => {
150
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
151
- const errorObject = err!;
152
- errorObject.message = `${errorObject.message} (${timeout}ms)`;
153
- reject(err);
154
- };
155
- const timer = setTimeout(
156
- () => timeoutOptions.reject === false ? resolve(timeoutOptions.value) : timeoutRejections(),
157
- timeout);
158
-
159
- executor(
160
- (value) => {
161
- clearTimeout(timer);
162
- resolve(value);
163
- },
164
- (reason) => {
165
- clearTimeout(timer);
166
- reject(reason);
167
- });
168
- });
151
+ const timeout = timeoutOptions.durationMs ?? 0;
152
+ if (timeout <= 0 || !Number.isFinite(timeout)) {
153
+ return new Promise(executor);
154
+ }
155
+
156
+ return new Promise<T>((resolve, reject) => {
157
+ const timeoutRejections = () => {
158
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
159
+ const errorObject = err!;
160
+ errorObject.message = `${errorObject.message} (${timeout}ms)`;
161
+ reject(err);
162
+ };
163
+ const timer = setTimeout(
164
+ () =>
165
+ timeoutOptions.reject === false
166
+ ? resolve(timeoutOptions.value)
167
+ : timeoutRejections(),
168
+ timeout,
169
+ );
170
+
171
+ executor(
172
+ (value) => {
173
+ clearTimeout(timer);
174
+ resolve(value);
175
+ },
176
+ (reason) => {
177
+ clearTimeout(timer);
178
+ reject(reason);
179
+ },
180
+ );
181
+ });
169
182
  }
170
183
 
171
184
  // Create a promise based on test timeout and the timeout options
172
185
  export async function timeoutPromise<T = void>(
173
- executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void,
174
- timeoutOptions: TimeoutWithError | TimeoutWithValue<T> = {},
186
+ executor: (
187
+ resolve: (value: T | PromiseLike<T>) => void,
188
+ reject: (reason?: any) => void,
189
+ ) => void,
190
+ timeoutOptions: TimeoutWithError | TimeoutWithValue<T> = {},
175
191
  ): Promise<T> {
176
- // create the timeout error outside the async task, so its callstack includes
177
- // the original call site, this makes it easier to debug
178
- const err = timeoutOptions.reject === false
179
- ? undefined
180
- : new Error(timeoutOptions.errorMsg ?? "Timed out");
181
- const executorPromise = getTimeoutPromise(executor, timeoutOptions, err);
182
-
183
- const currentTestTimeout = TestTimeout.getInstance();
184
- if (currentTestTimeout === undefined) { return executorPromise; }
185
-
186
- return Promise.race([executorPromise, currentTestTimeout.getPromise()]).catch((e) => {
187
- if (e === currentTestTimeout) {
188
- if (timeoutOptions.reject !== false) {
189
- // If the rejection is because of the timeout then
190
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
191
- const errorObject = err!;
192
- errorObject.message =
193
- `${timeoutOptions.errorMsg ?? "Test timed out"} (${currentTestTimeout.getTimeout()}ms)`;
194
- throw errorObject;
195
- }
196
- return timeoutOptions.value;
197
- }
198
- throw e;
199
- }) as Promise<T>;
192
+ // create the timeout error outside the async task, so its callstack includes
193
+ // the original call site, this makes it easier to debug
194
+ const err =
195
+ timeoutOptions.reject === false
196
+ ? undefined
197
+ : new Error(timeoutOptions.errorMsg ?? "Timed out");
198
+ const executorPromise = getTimeoutPromise(executor, timeoutOptions, err);
199
+
200
+ const currentTestTimeout = TestTimeout.getInstance();
201
+ if (currentTestTimeout === undefined) {
202
+ return executorPromise;
203
+ }
204
+
205
+ return Promise.race([executorPromise, currentTestTimeout.getPromise()]).catch((e) => {
206
+ if (e === currentTestTimeout) {
207
+ if (timeoutOptions.reject !== false) {
208
+ // If the rejection is because of the timeout then
209
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
210
+ const errorObject = err!;
211
+ errorObject.message = `${
212
+ timeoutOptions.errorMsg ?? "Test timed out"
213
+ } (${currentTestTimeout.getTimeout()}ms)`;
214
+ throw errorObject;
215
+ }
216
+ return timeoutOptions.value;
217
+ }
218
+ throw e;
219
+ }) as Promise<T>;
200
220
  }
package/tsconfig.json CHANGED
@@ -1,18 +1,11 @@
1
1
  {
2
- "extends": "@fluidframework/build-common/ts-common-config.json",
3
- "exclude": [
4
- "src/test/**/*"
5
- ],
6
- "compilerOptions": {
7
- "rootDir": "./src",
8
- "outDir": "./dist",
9
- "composite": true,
10
- "types": [
11
- "mocha",
12
- "node"
13
- ]
14
- },
15
- "include": [
16
- "src/**/*"
17
- ]
2
+ "extends": "@fluidframework/build-common/ts-common-config.json",
3
+ "exclude": ["src/test/**/*"],
4
+ "compilerOptions": {
5
+ "rootDir": "./src",
6
+ "outDir": "./dist",
7
+ "composite": true,
8
+ "types": ["mocha", "node"],
9
+ },
10
+ "include": ["src/**/*"],
18
11
  }