Kaynağa Gözat

fix(testing): Await outstanding jobs before populating test data (#3544)

Michael Bromley 8 ay önce
ebeveyn
işleme
cc32ce762c

+ 1 - 7
packages/core/e2e/custom-field-relations.e2e-spec.ts

@@ -4,15 +4,12 @@ import {
     Collection,
     Country,
     CustomFields,
-    DefaultLogger,
     defaultShippingCalculator,
     defaultShippingEligibilityChecker,
     Facet,
     FacetValue,
-    LogLevel,
     manualFulfillmentHandler,
     mergeConfig,
-    PluginCommonModule,
     Product,
     ProductOption,
     ProductOptionGroup,
@@ -20,8 +17,6 @@ import {
     RequestContext,
     ShippingMethod,
     TransactionalConnection,
-    VendureEntity,
-    VendurePlugin,
 } from '@vendure/core';
 import { createTestEnvironment } from '@vendure/testing';
 import gql from 'graphql-tag';
@@ -30,7 +25,7 @@ import { Repository } from 'typeorm';
 import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 import { initialData } from '../../../e2e-common/e2e-initial-data';
-import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
+import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
 
 import { testSuccessfulPaymentMethod } from './fixtures/test-payment-methods';
 import { TestPlugin1636_1664 } from './fixtures/test-plugins/issue-1636-1664/issue-1636-1664-plugin';
@@ -102,7 +97,6 @@ const customConfig = mergeConfig(testConfig(), {
     paymentOptions: {
         paymentMethodHandlers: [testSuccessfulPaymentMethod],
     },
-    // logger: new DefaultLogger({ level: LogLevel.Debug }),
     dbConnectionOptions: {
         timezone: 'Z',
     },

+ 36 - 1
packages/testing/src/data-population/populate-for-testing.ts

@@ -1,7 +1,7 @@
 /* eslint-disable no-console */
 import { INestApplicationContext } from '@nestjs/common';
 import { LanguageCode } from '@vendure/common/lib/generated-types';
-import { VendureConfig } from '@vendure/core';
+import { ConfigService, isInspectableJobQueueStrategy, VendureConfig } from '@vendure/core';
 import { importProductsFromCsv, populateCollections, populateInitialData } from '@vendure/core/cli';
 
 import { TestServerOptions } from '../types';
@@ -23,6 +23,7 @@ export async function populateForTesting<T extends INestApplicationContext>(
     config.authOptions.requireVerification = false;
 
     const app = await bootstrapFn(config);
+    await awaitOutstandingJobs(app);
 
     const logFn = (message: string) => (logging ? console.log(message) : null);
 
@@ -35,6 +36,40 @@ export async function populateForTesting<T extends INestApplicationContext>(
     return app;
 }
 
+/**
+ * Sometimes there will be jobs created during the bootstrap process, e.g. when
+ * a plugin needs to create certain entities during bootstrap, which might then
+ * trigger e.g. search index update jobs. This can lead to very hard-to-debug
+ * failures in e2e tests suites (specifically at this moment, consistent failures
+ * of the sql.js tests on Node v20).
+ *
+ * This function will wait for all outstanding jobs to finish before returning.
+ */
+async function awaitOutstandingJobs(app: INestApplicationContext) {
+    const { jobQueueStrategy } = app.get(ConfigService).jobQueueOptions;
+    const maxAttempts = 10;
+    let attempts = 0;
+    if (isInspectableJobQueueStrategy(jobQueueStrategy)) {
+        const inspectableJobQueueStrategy = jobQueueStrategy;
+
+        function waitForJobQueueToBeIdle() {
+            return new Promise<void>(resolve => {
+                const interval = setInterval(async () => {
+                    attempts++;
+                    const { items } = await inspectableJobQueueStrategy.findMany();
+                    const jobsOutstanding = items.filter(i => i.state === 'RUNNING' || i.state === 'PENDING');
+                    if (jobsOutstanding.length === 0 || attempts >= maxAttempts) {
+                        clearInterval(interval);
+                        resolve();
+                    }
+                }, 500);
+            });
+        }
+
+        await waitForJobQueueToBeIdle();
+    }
+}
+
 async function populateProducts(
     app: INestApplicationContext,
     productsCsvPath: string | undefined,