apify-test-tools 0.3.0 → 0.4.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.
@@ -117,6 +117,8 @@ export const extendExpect = (expect: ExpectStatic): ExpectStatic => {
117
117
  ...userOptions,
118
118
  };
119
119
 
120
+ const failedAssertions: string[] = [];
121
+
120
122
  const diffs: Diffs = {
121
123
  pass: true,
122
124
  actual: ['Run:'],
@@ -125,9 +127,13 @@ export const extendExpect = (expect: ExpectStatic): ExpectStatic => {
125
127
  {
126
128
  const expected = options?.status;
127
129
  const actual = received.status;
128
- diffs.pass = expected === actual;
129
- diffs.actual.push(`status=${actual}`);
130
- diffs.expected.push(`status=${expected}`);
130
+ const statusTest = expected === actual;
131
+ if (statusTest === false) {
132
+ diffs.pass = false;
133
+ diffs.actual.push(`status=${actual}`);
134
+ diffs.expected.push(`status=${expected}`);
135
+ failedAssertions.push(`Failed status check, expected "${expected}", got "${actual}".`);
136
+ }
131
137
  }
132
138
 
133
139
  const {
@@ -135,12 +141,23 @@ export const extendExpect = (expect: ExpectStatic): ExpectStatic => {
135
141
  stats: { durationMillis },
136
142
  } = await received.getRunInfo();
137
143
  const datasetItemCount = (await received.getDataset()).items.length;
138
- const stats = (await received.getStatistics());
144
+ const stats = await received.getStatistics();
139
145
 
140
- isWithinInterval(diffs, datasetItemCount, options, 'datasetItemCount');
141
- isWithinInterval(diffs, durationMillis, options, 'duration');
142
- isWithinInterval(diffs, stats?.requestsFailed, options, 'failedRequests');
143
- isWithinInterval(diffs, stats?.requestsRetries, options, 'requestsRetries');
146
+ const checkInterval = (
147
+ value: number | undefined,
148
+ key: ['datasetItemCount', 'duration', 'failedRequests', 'requestsRetries'][number],
149
+ label: string,
150
+ ) => {
151
+ const result = isWithinInterval(diffs, value, options, key);
152
+ if (result === false) {
153
+ failedAssertions.push(`Failed ${label} check, expected ${JSON.stringify(options[key])}, got ${value}.`);
154
+ }
155
+ };
156
+
157
+ checkInterval(datasetItemCount, 'datasetItemCount', 'dataset item count');
158
+ checkInterval(durationMillis, 'duration', 'duration');
159
+ checkInterval(stats?.requestsFailed, 'failedRequests', 'failed requests');
160
+ checkInterval(stats?.requestsRetries, 'requestsRetries', 'requests retries');
144
161
 
145
162
  const ppeDiffs: Diffs = {
146
163
  pass: true,
@@ -175,9 +192,12 @@ export const extendExpect = (expect: ExpectStatic): ExpectStatic => {
175
192
  isWithinInterval(ppeDiffs, actual[ppeEvent], expected, ppeEvent as PpeEvent);
176
193
  }
177
194
 
178
- diffs.pass = diffs.pass && ppeDiffs.pass;
179
- diffs.actual.push(ppeDiffs.actual.join('\n '));
180
- diffs.expected.push(ppeDiffs.expected.join('\n '));
195
+ if (ppeDiffs.pass === false) {
196
+ diffs.pass = ppeDiffs.pass;
197
+ diffs.actual.push(ppeDiffs.actual.join('\n '));
198
+ diffs.expected.push(ppeDiffs.expected.join('\n '));
199
+ failedAssertions.push(`Failed PPE event counts check, expected ${JSON.stringify(options.chargedEventCounts)}, got ${JSON.stringify(chargedEventCounts)}.`);
200
+ }
181
201
  }
182
202
 
183
203
  {
@@ -193,12 +213,13 @@ export const extendExpect = (expect: ExpectStatic): ExpectStatic => {
193
213
  diffs.pass = false;
194
214
  diffs.actual.push(` logs=[${occuredLogs.join(', ')}]`);
195
215
  diffs.expected.push(` logs=[]`);
216
+ failedAssertions.push(`Failed forbidden logs check, expected [] but got [${occuredLogs.join(', ')}].`);
196
217
  }
197
218
  }
198
219
 
199
220
  return {
200
221
  pass: diffs.pass,
201
- message: () => `Run ${received.id} didn't finish as expected`,
222
+ message: () => `Run did not finish as expected. Failed assertions: ${failedAssertions.join(' ',)}`,
202
223
  actual: diffs.actual.join('\n '),
203
224
  expected: diffs.expected.join('\n '),
204
225
  };
@@ -256,6 +277,7 @@ const isWithinInterval = <T extends string>(
256
277
  diffs.pass = false;
257
278
  diffs.actual.push(`${intervalOption}=${actual}`);
258
279
  diffs.expected.push(`${intervalOption}=${expected}`);
280
+ return false
259
281
  }
260
282
  } else if (typeof expected === 'object') {
261
283
  const { min, max } = expected;
@@ -263,6 +285,8 @@ const isWithinInterval = <T extends string>(
263
285
  diffs.pass = false;
264
286
  diffs.actual.push(`${intervalOption}=${actual}`);
265
287
  diffs.expected.push(`${intervalOption}=<${min ?? ''},${max ?? ''}>`);
288
+ return false
266
289
  }
267
290
  }
291
+ return
268
292
  };
package/lib/lib.ts CHANGED
@@ -5,10 +5,9 @@ import {
5
5
  TestFunction,
6
6
  test as vitestTest,
7
7
  SuiteFactory,
8
- TestOptions,
9
8
  TestContext,
10
9
  } from 'vitest';
11
- import type { ActorBuild, RunOptions } from './types';
10
+ import type { ActorBuild, ActorTestOptions, RunOptions } from './types';
12
11
  import { RunTestResult } from './run-test-result.js';
13
12
  import { extendExpect } from './extend-expect.js';
14
13
  import { getActorPrefilledInput, sleep } from './utils.js';
@@ -38,7 +37,7 @@ export { ExpectStatic };
38
37
  const { TESTER_APIFY_TOKEN, RUN_PLATFORM_TESTS, RUN_ALL_PLATFORM_TESTS } = process.env;
39
38
  const apifyClient = new ApifyClient({ token: TESTER_APIFY_TOKEN });
40
39
 
41
- const DEFAULT_TEST_OPTIONS: TestOptions = {
40
+ const DEFAULT_TEST_OPTIONS: ActorTestOptions = {
42
41
  // we want to run tests concurrently
43
42
  concurrent: true,
44
43
  // test should finish within 1 hour
@@ -48,12 +47,12 @@ const DEFAULT_TEST_OPTIONS: TestOptions = {
48
47
  export const describe = (
49
48
  name: string,
50
49
  fn?: SuiteFactory<object>,
51
- options: TestOptions = DEFAULT_TEST_OPTIONS,
50
+ options: ActorTestOptions = DEFAULT_TEST_OPTIONS,
52
51
  ) => {
53
52
  vitestDescribe.runIf(!!RUN_PLATFORM_TESTS || !!RUN_ALL_PLATFORM_TESTS)(name, options, fn);
54
53
  };
55
54
 
56
- const DEFAULT_TEST_ACTOR_OPTIONS: TestOptions = {
55
+ const DEFAULT_TEST_ACTOR_OPTIONS: ActorTestOptions = {
57
56
  retry: 1,
58
57
  };
59
58
 
@@ -61,7 +60,7 @@ export const testActor = <T>(
61
60
  actorName: string,
62
61
  testName: string,
63
62
  fn: TestFunction<{ run: ReturnType<typeof createStartRunFn<T>> }>,
64
- testOptions?: TestOptions,
63
+ testOptions?: ActorTestOptions,
65
64
  ) => {
66
65
  const options = {
67
66
  ...DEFAULT_TEST_ACTOR_OPTIONS,
@@ -90,7 +89,7 @@ export const testStandbyActor = <I = any, O = any>(
90
89
  actorName: string,
91
90
  testName: string,
92
91
  fn: TestFunction<{ callStandby: ReturnType<typeof createStartStandbyFn<I, O>> }>,
93
- testOptions?: TestOptions,
92
+ testOptions?: ActorTestOptions,
94
93
  ) => {
95
94
  const options = {
96
95
  ...DEFAULT_TEST_ACTOR_OPTIONS,
package/lib/types.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ActorCallOptions } from 'apify-client';
2
- import { Assertion } from 'vitest';
2
+ import { Assertion, TestOptions } from 'vitest';
3
3
 
4
4
  export type ActorBuild = {
5
5
  buildId: string;
@@ -131,6 +131,17 @@ export interface ActorMatchers<R = unknown> {
131
131
  hard: <T>(actual: T, message?: string) => Assertion
132
132
  }
133
133
 
134
+ export type ActorTestOptions = Omit<TestOptions, 'retry'> & {
135
+ /**
136
+ * Times to retry the test if fails. Useful for making flaky tests more stable.
137
+ * When retries is up, the last test error will be thrown.
138
+ *
139
+ * @default 1
140
+ */
141
+ // we are just extending the docs here to replace the default value, otherwise it's the exact same
142
+ retry?: TestOptions['retry'];
143
+ };
144
+
134
145
  declare module 'vitest' {
135
146
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
136
147
  interface Assertion<T = any> extends ActorMatchers<T> { }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apify-test-tools",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "TBD",
6
6
  "engines": {