Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
*/
export const TEST_SETUP_TIMEOUT_MS = process.env.E2E_DEBUG ? 1800 * 1000 : 120000;
/**
* For local debugging of the e2e tests, we set a very long timeout value otherwise tests will
* automatically fail for going over the 5 second default timeout.
*/
if (process.env.E2E_DEBUG) {
// tslint:disable-next-line:no-console
console.log('E2E_DEBUG', process.env.E2E_DEBUG, ' - setting long timeout');
jest.setTimeout(1800 * 1000);
}
const packageDir = getPackageDir();
export const testConfig = mergeConfig(defaultTestConfig, {
importExportOptions: {
importAssetsDir: path.join(packageDir, 'fixtures/assets'),
},
});
}
if (!index.config) {
console.error(`The file "${configFile}" does not export a "config" object`);
process.exit(1);
return;
}
const config = index.config;
// Force the sync mode on, so that all the tables are created
// on this initial run.
config.dbConnectionOptions.synchronize = true;
const { bootstrap } = require('@vendure/core');
console.log('Bootstrapping Vendure server...');
const app = await bootstrap(config);
return app;
}
UpdateAddress,
UpdateCustomer,
} from './graphql/generated-e2e-admin-types';
import { AddItemToOrder } from './graphql/generated-e2e-shop-types';
import { GET_CUSTOMER, GET_CUSTOMER_LIST } from './graphql/shared-definitions';
import { ADD_ITEM_TO_ORDER } from './graphql/shop-definitions';
import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
// tslint:disable:no-non-null-assertion
let sendEmailFn: jest.Mock;
/**
* This mock plugin simulates an EmailPlugin which would send emails
* on the registration & password reset events.
*/
@VendurePlugin({
imports: [EventBusModule],
})
class TestEmailPlugin implements OnModuleInit {
constructor(private eventBus: EventBus) {}
onModuleInit() {
this.eventBus.ofType(AccountRegistrationEvent).subscribe(event => {
sendEmailFn(event);
});
}
}
describe('Customer resolver', () => {
const { server, adminClient, shopClient } = createTestEnvironment(
mergeConfig(testConfig, { plugins: [TestEmailPlugin] }),
);
*
* @example
* ```ts
* import { AdminUiPlugin } from '\@vendure/admin-ui-plugin';
*
* const config: VendureConfig = {
* // Add an instance of the plugin to the plugins array
* plugins: [
* AdminUiPlugin.init({ port: 3002 }),
* ],
* };
* ```
*
* @docsCategory AdminUiPlugin
*/
@VendurePlugin({
imports: [PluginCommonModule],
providers: [UiAppCompiler],
configuration: config => AdminUiPlugin.configure(config),
})
export class AdminUiPlugin implements OnVendureBootstrap, OnVendureClose {
private static options: AdminUiOptions;
private server: Server;
private watcher: Watcher | undefined;
constructor(private configService: ConfigService, private appCompiler: UiAppCompiler) {}
/**
* @description
* Set the plugin options
*/
static init(options: AdminUiOptions): Type {
import { bootstrap } from '@vendure/core';
import { devConfig } from './dev-config';
/**
* This bootstraps the dev server, used for testing Vendure during development.
*/
bootstrap(devConfig).catch(err => {
// tslint:disable-next-line
console.log(err);
});
dbConnectionOptions: {
synchronize: false,
logging: false,
migrations: [path.join(__dirname, 'migrations/*.ts')],
...getDbConfig(),
},
paymentOptions: {
paymentMethodHandlers: [examplePaymentHandler],
},
customFields: {
/*Product: [
{ name: 'rating', type: 'float', readonly: true },
{ name: 'markup', type: 'float', internal: true },
],*/
},
logger: new DefaultLogger({ level: LogLevel.Info }),
importExportOptions: {
importAssetsDir: path.join(__dirname, 'import-assets'),
},
plugins: [
AssetServerPlugin.init({
route: 'assets',
assetUploadDir: path.join(__dirname, 'assets'),
port: 5002,
}),
DefaultSearchPlugin,
// ElasticsearchPlugin.init({
// host: 'http://192.168.99.100',
// port: 9200,
// }),
EmailPlugin.init({
devMode: true,
(async () => {
const timeStart = Date.now();
if (ids.length) {
const batches = Math.ceil(ids.length / batchSize);
Logger.verbose(`Updating ${ids.length} variants...`);
let variantsInProduct: ProductVariant[] = [];
for (let i = 0; i < batches; i++) {
const begin = i * batchSize;
const end = begin + batchSize;
Logger.verbose(`Updating ids from index ${begin} to ${end}`);
const batchIds = ids.slice(begin, end);
const variants = await this.getVariantsByIds(ctx, batchIds);
const variantsToIndex: Array> = [];
const productsToIndex: Array> = [];
// tslint:disable-next-line:prefer-for-of
for (let j = 0; j < variants.length; j++) {
const variant = variants[j];
variantsInProduct.push(variant);
variantsToIndex.push({ update: { _id: variant.id.toString() } });
variantsToIndex.push({ doc: this.createVariantIndexItem(variant) });
const nextVariant = variants[j + 1];
if (nextVariant && nextVariant.productId !== variant.productId) {
(async () => {
const timeStart = Date.now();
const qb = this.getSearchIndexQueryBuilder();
const count = await qb.where('variants__product.deletedAt IS NULL').getCount();
Logger.verbose(`Reindexing ${count} ProductVariants`, loggerCtx);
const batches = Math.ceil(count / batchSize);
let variantsInProduct: ProductVariant[] = [];
for (let i = 0; i < batches; i++) {
Logger.verbose(`Processing batch ${i + 1} of ${batches}`, loggerCtx);
const variants = await this.getBatch(ctx, qb, i);
Logger.verbose(`ProductVariants count: ${variants.length}`);
const variantsToIndex: Array = [];
const productsToIndex: Array = [];
// tslint:disable-next-line:prefer-for-of
for (let j = 0; j < variants.length; j++) {
const variant = variants[j];
* "score": 30.58831,
* "price": {
* "min": 4984,
* "max": 4984
* }
* },
* // ... truncated
* ]
* }
* }
*}
* ```
*
* @docsCategory ElasticsearchPlugin
*/
@VendurePlugin({
imports: [PluginCommonModule],
providers: [
ElasticsearchIndexService,
ElasticsearchService,
{ provide: ELASTIC_SEARCH_OPTIONS, useFactory: () => ElasticsearchPlugin.options },
{ provide: ELASTIC_SEARCH_CLIENT, useFactory: () => ElasticsearchPlugin.client },
],
adminApiExtensions: { resolvers: [AdminElasticSearchResolver] },
shopApiExtensions: {
resolvers: () => {
const { options } = ElasticsearchPlugin;
const requiresUnionResolver =
0 < Object.keys(options.customProductMappings || {}).length &&
0 < Object.keys(options.customProductVariantMappings || {}).length;
return requiresUnionResolver
? [ShopElasticSearchResolver, CustomMappingsResolver]
@ResolveProperty()
async prices(
@Ctx() ctx: RequestContext,
@Parent() parent: { input: ElasticSearchInput },
): Promise {
return this.elasticsearchService.priceRange(ctx, parent.input);
}
}
@Resolver('SearchResponse')
export class AdminElasticSearchResolver implements SearchResolver {
constructor(private elasticsearchService: ElasticsearchService) {}
@Query()
@Allow(Permission.ReadCatalog)
async search(
@Ctx() ctx: RequestContext,
@Args() args: QuerySearchArgs,
): Promise> {
const result = await this.elasticsearchService.search(ctx, args.input, false);
// ensure the facetValues property resolver has access to the input args
(result as any).input = args.input;
return result;
}
@ResolveProperty()
async facetValues(
@Ctx() ctx: RequestContext,
@Parent() parent: { input: SearchInput },
): Promise> {
return this.elasticsearchService.facetValues(ctx, parent.input, false);