|
|
@@ -1,13 +1,15 @@
|
|
|
import { KeyValueCache } from '@apollo/utils.keyvaluecache';
|
|
|
import { mergeConfig } from '@vendure/core';
|
|
|
import { createTestEnvironment } from '@vendure/testing';
|
|
|
-import gql from 'graphql-tag';
|
|
|
import path from 'path';
|
|
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
|
|
|
|
import { initialData } from '../../../e2e-common/e2e-initial-data';
|
|
|
import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
|
|
|
|
|
|
+import * as Codegen from './graphql/generated-e2e-admin-types';
|
|
|
+import { GET_PRODUCT_LIST, GET_PRODUCT_SIMPLE } from './graphql/shared-definitions';
|
|
|
+
|
|
|
class MockCache implements KeyValueCache<string> {
|
|
|
static getCalls: Array<{ key: string; result: string | undefined }> = [];
|
|
|
static setCalls: Array<{ key: string; value: string; options?: { ttl?: number } }> = [];
|
|
|
@@ -21,25 +23,26 @@ class MockCache implements KeyValueCache<string> {
|
|
|
this.deleteCalls = [];
|
|
|
}
|
|
|
|
|
|
- async get(key: string): Promise<string | undefined> {
|
|
|
+ get(key: string): Promise<string | undefined> {
|
|
|
// eslint-disable-next-line
|
|
|
console.log(`MockCache get: ${key}`);
|
|
|
const result = this.store.get(key);
|
|
|
MockCache.getCalls.push({ key, result });
|
|
|
- return result;
|
|
|
+ return Promise.resolve(result);
|
|
|
}
|
|
|
|
|
|
- async set(key: string, value: string, options?: { ttl?: number }): Promise<void> {
|
|
|
+ set(key: string, value: string, options?: { ttl?: number }): Promise<void> {
|
|
|
// eslint-disable-next-line
|
|
|
console.log(`MockCache set: ${key}`, value);
|
|
|
this.store.set(key, value);
|
|
|
MockCache.setCalls.push({ key, value, options });
|
|
|
+ return Promise.resolve();
|
|
|
}
|
|
|
|
|
|
- async delete(key: string): Promise<boolean> {
|
|
|
+ delete(key: string): Promise<boolean> {
|
|
|
const result = this.store.delete(key);
|
|
|
MockCache.deleteCalls.push({ key, result });
|
|
|
- return result;
|
|
|
+ return Promise.resolve(result);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -71,80 +74,67 @@ describe('Apollo cache configuration', () => {
|
|
|
MockCache.reset();
|
|
|
|
|
|
// Make a GraphQL query that could potentially be cached
|
|
|
- const result = await shopClient.query(gql`
|
|
|
- query GetProduct {
|
|
|
- product(id: "T_1") {
|
|
|
- id
|
|
|
- name
|
|
|
- slug
|
|
|
- }
|
|
|
- }
|
|
|
- `);
|
|
|
+ const result = await shopClient.query<
|
|
|
+ Codegen.GetProductListQuery,
|
|
|
+ Codegen.GetProductListQueryVariables
|
|
|
+ >(GET_PRODUCT_LIST, {
|
|
|
+ options: {
|
|
|
+ filter: { id: { eq: 'T_1' } },
|
|
|
+ take: 1,
|
|
|
+ },
|
|
|
+ });
|
|
|
|
|
|
- expect(result.product).toBeDefined();
|
|
|
- expect(result.product.id).toBe('T_1');
|
|
|
- expect(result.product.name).toBe('Laptop');
|
|
|
+ expect(result.products.items.length).toBe(1);
|
|
|
+ expect(result.products.items[0].id).toBe('T_1');
|
|
|
+ expect(result.products.items[0].name).toBe('Laptop');
|
|
|
});
|
|
|
|
|
|
it('should handle cache operations without errors', async () => {
|
|
|
MockCache.reset();
|
|
|
|
|
|
// Test multiple queries to potentially trigger cache operations
|
|
|
- await shopClient.query(gql`
|
|
|
- query GetProducts {
|
|
|
- products(options: { take: 5 }) {
|
|
|
- items {
|
|
|
- id
|
|
|
- name
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- `);
|
|
|
-
|
|
|
- await adminClient.query(gql`
|
|
|
- query GetProducts {
|
|
|
- products(options: { take: 3 }) {
|
|
|
- items {
|
|
|
- id
|
|
|
- name
|
|
|
- slug
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- `);
|
|
|
+ const shopResponse = await shopClient.query<
|
|
|
+ Codegen.GetProductListQuery,
|
|
|
+ Codegen.GetProductListQueryVariables
|
|
|
+ >(GET_PRODUCT_LIST, {
|
|
|
+ options: {
|
|
|
+ take: 1,
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(shopResponse.products.items.length).toBe(1);
|
|
|
+
|
|
|
+ const adminResponse = await adminClient.query<
|
|
|
+ Codegen.GetProductListQuery,
|
|
|
+ Codegen.GetProductListQueryVariables
|
|
|
+ >(GET_PRODUCT_LIST, {
|
|
|
+ options: { take: 1 },
|
|
|
+ });
|
|
|
|
|
|
- // The cache instance should be properly configured and accessible
|
|
|
- // We don't verify specific cache calls as Apollo Server's internal
|
|
|
- // caching behavior may vary, but we ensure no errors occur
|
|
|
- expect(true).toBe(true); // Test passes if no errors thrown
|
|
|
+ expect(adminResponse.products.items.length).toBe(1);
|
|
|
});
|
|
|
|
|
|
it('should work with both shop and admin APIs', async () => {
|
|
|
MockCache.reset();
|
|
|
|
|
|
const [shopResult, adminResult] = await Promise.all([
|
|
|
- shopClient.query(gql`
|
|
|
- query ShopQuery {
|
|
|
- product(id: "T_1") {
|
|
|
- id
|
|
|
- name
|
|
|
- }
|
|
|
- }
|
|
|
- `),
|
|
|
- adminClient.query(gql`
|
|
|
- query AdminQuery {
|
|
|
- product(id: "T_1") {
|
|
|
- id
|
|
|
- name
|
|
|
- slug
|
|
|
- }
|
|
|
- }
|
|
|
- `),
|
|
|
+ shopClient.query<Codegen.GetProductSimpleQuery, Codegen.GetProductSimpleQueryVariables>(
|
|
|
+ GET_PRODUCT_SIMPLE,
|
|
|
+ {
|
|
|
+ id: 'T_1',
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ adminClient.query<Codegen.GetProductSimpleQuery, Codegen.GetProductSimpleQueryVariables>(
|
|
|
+ GET_PRODUCT_SIMPLE,
|
|
|
+ {
|
|
|
+ id: 'T_1',
|
|
|
+ },
|
|
|
+ ),
|
|
|
]);
|
|
|
|
|
|
expect(shopResult.product).toBeDefined();
|
|
|
expect(adminResult.product).toBeDefined();
|
|
|
- expect(shopResult.product.id).toBe(adminResult.product.id);
|
|
|
+ expect(shopResult.product?.id).toBe(adminResult.product?.id);
|
|
|
});
|
|
|
});
|
|
|
|
|
|
@@ -171,29 +161,25 @@ describe('Apollo cache configuration', () => {
|
|
|
});
|
|
|
|
|
|
it('should configure Apollo Server with bounded cache', async () => {
|
|
|
- const result = await shopClient.query(gql`
|
|
|
- query GetProduct {
|
|
|
- product(id: "T_1") {
|
|
|
- id
|
|
|
- name
|
|
|
- }
|
|
|
- }
|
|
|
- `);
|
|
|
+ const result = await shopClient.query<
|
|
|
+ Codegen.GetProductSimpleQuery,
|
|
|
+ Codegen.GetProductSimpleQueryVariables
|
|
|
+ >(GET_PRODUCT_SIMPLE, {
|
|
|
+ id: 'T_1',
|
|
|
+ });
|
|
|
|
|
|
expect(result.product).toBeDefined();
|
|
|
- expect(result.product.id).toBe('T_1');
|
|
|
+ expect(result.product?.id).toBe('T_1');
|
|
|
});
|
|
|
|
|
|
it('should handle concurrent requests with bounded cache', async () => {
|
|
|
const queries = Array.from({ length: 5 }, (_, i) =>
|
|
|
- shopClient.query(gql`
|
|
|
- query GetProduct${i} {
|
|
|
- product(id: "T_${i + 1}") {
|
|
|
- id
|
|
|
- name
|
|
|
- }
|
|
|
- }
|
|
|
- `),
|
|
|
+ shopClient.query<Codegen.GetProductSimpleQuery, Codegen.GetProductSimpleQueryVariables>(
|
|
|
+ GET_PRODUCT_SIMPLE,
|
|
|
+ {
|
|
|
+ id: `T_${i + 1}`,
|
|
|
+ },
|
|
|
+ ),
|
|
|
);
|
|
|
|
|
|
const results = await Promise.all(queries);
|
|
|
@@ -223,17 +209,15 @@ describe('Apollo cache configuration', () => {
|
|
|
});
|
|
|
|
|
|
it('should work without cache configuration', async () => {
|
|
|
- const result = await shopClient.query(gql`
|
|
|
- query GetProduct {
|
|
|
- product(id: "T_1") {
|
|
|
- id
|
|
|
- name
|
|
|
- }
|
|
|
- }
|
|
|
- `);
|
|
|
+ const result = await shopClient.query<
|
|
|
+ Codegen.GetProductSimpleQuery,
|
|
|
+ Codegen.GetProductSimpleQueryVariables
|
|
|
+ >(GET_PRODUCT_SIMPLE, {
|
|
|
+ id: 'T_1',
|
|
|
+ });
|
|
|
|
|
|
expect(result.product).toBeDefined();
|
|
|
- expect(result.product.id).toBe('T_1');
|
|
|
+ expect(result.product?.id).toBe('T_1');
|
|
|
});
|
|
|
});
|
|
|
});
|