error-handler-strategy.e2e-spec.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import { ArgumentsHost, OnApplicationBootstrap } from '@nestjs/common';
  2. import { Mutation, Resolver } from '@nestjs/graphql';
  3. import {
  4. mergeConfig,
  5. Job,
  6. ErrorHandlerStrategy,
  7. VendurePlugin,
  8. PluginCommonModule,
  9. JobQueueService,
  10. JobQueue,
  11. } from '@vendure/core';
  12. import { createTestEnvironment } from '@vendure/testing';
  13. import gql from 'graphql-tag';
  14. import path from 'path';
  15. import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
  16. import { initialData } from '../../../e2e-common/e2e-initial-data';
  17. import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
  18. import { awaitRunningJobs } from './utils/await-running-jobs';
  19. class TestErrorHandlerStrategy implements ErrorHandlerStrategy {
  20. static serverErrorSpy = vi.fn();
  21. static workerErrorSpy = vi.fn();
  22. handleServerError(exception: Error, context: { host: ArgumentsHost }) {
  23. TestErrorHandlerStrategy.serverErrorSpy(exception, context);
  24. }
  25. handleWorkerError(exception: Error, context: { job: Job }) {
  26. TestErrorHandlerStrategy.workerErrorSpy(exception, context);
  27. }
  28. }
  29. @Resolver()
  30. class TestResolver implements OnApplicationBootstrap {
  31. private queue: JobQueue<any>;
  32. constructor(private jobQueueService: JobQueueService) {}
  33. async onApplicationBootstrap() {
  34. this.queue = await this.jobQueueService.createQueue({
  35. name: 'test-queue',
  36. process: async () => {
  37. throw new Error('worker error');
  38. },
  39. });
  40. }
  41. @Mutation()
  42. createServerError() {
  43. throw new Error('server error');
  44. }
  45. @Mutation()
  46. createWorkerError() {
  47. return this.queue.add({});
  48. }
  49. }
  50. @VendurePlugin({
  51. imports: [PluginCommonModule],
  52. adminApiExtensions: {
  53. schema: gql`
  54. extend type Mutation {
  55. createServerError: Boolean!
  56. createWorkerError: Job!
  57. }
  58. `,
  59. resolvers: [TestResolver],
  60. },
  61. })
  62. class TestErrorMakingPlugin {}
  63. describe('ErrorHandlerStrategy', () => {
  64. const { server, adminClient, shopClient } = createTestEnvironment(
  65. mergeConfig(testConfig(), {
  66. systemOptions: {
  67. errorHandlers: [new TestErrorHandlerStrategy()],
  68. },
  69. plugins: [TestErrorMakingPlugin],
  70. }),
  71. );
  72. beforeAll(async () => {
  73. await server.init({
  74. initialData,
  75. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
  76. customerCount: 1,
  77. });
  78. await adminClient.asSuperAdmin();
  79. }, TEST_SETUP_TIMEOUT_MS);
  80. beforeEach(() => {
  81. TestErrorHandlerStrategy.serverErrorSpy.mockClear();
  82. TestErrorHandlerStrategy.workerErrorSpy.mockClear();
  83. });
  84. afterAll(async () => {
  85. await server.destroy();
  86. });
  87. it('no error handler have initially been called', async () => {
  88. expect(TestErrorHandlerStrategy.serverErrorSpy).toHaveBeenCalledTimes(0);
  89. expect(TestErrorHandlerStrategy.workerErrorSpy).toHaveBeenCalledTimes(0);
  90. });
  91. it('invokes the server handler', async () => {
  92. try {
  93. await adminClient.query(gql`
  94. mutation {
  95. createServerError
  96. }
  97. `);
  98. } catch (e: any) {
  99. expect(e.message).toBe('server error');
  100. }
  101. expect(TestErrorHandlerStrategy.serverErrorSpy).toHaveBeenCalledTimes(1);
  102. expect(TestErrorHandlerStrategy.workerErrorSpy).toHaveBeenCalledTimes(0);
  103. expect(TestErrorHandlerStrategy.serverErrorSpy.mock.calls[0][0]).toBeInstanceOf(Error);
  104. expect(TestErrorHandlerStrategy.serverErrorSpy.mock.calls[0][0].message).toBe('server error');
  105. expect(TestErrorHandlerStrategy.serverErrorSpy.mock.calls[0][1].host).toBeDefined();
  106. });
  107. it('invokes the worker handler', async () => {
  108. await adminClient.query(gql`
  109. mutation {
  110. createWorkerError {
  111. id
  112. }
  113. }
  114. `);
  115. await awaitRunningJobs(adminClient);
  116. expect(TestErrorHandlerStrategy.serverErrorSpy).toHaveBeenCalledTimes(0);
  117. expect(TestErrorHandlerStrategy.workerErrorSpy).toHaveBeenCalledTimes(1);
  118. expect(TestErrorHandlerStrategy.workerErrorSpy.mock.calls[0][0]).toBeInstanceOf(Error);
  119. expect(TestErrorHandlerStrategy.workerErrorSpy.mock.calls[0][0].message).toBe('worker error');
  120. expect(TestErrorHandlerStrategy.workerErrorSpy.mock.calls[0][1].job).toHaveProperty(
  121. 'queueName',
  122. 'test-queue',
  123. );
  124. });
  125. });