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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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 handlers 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(
  94. gql`
  95. mutation {
  96. createServerError
  97. }
  98. `,
  99. );
  100. } catch (e: any) {
  101. expect(e.message).toBe('server error');
  102. }
  103. expect(TestErrorHandlerStrategy.serverErrorSpy).toHaveBeenCalledTimes(1);
  104. expect(TestErrorHandlerStrategy.workerErrorSpy).toHaveBeenCalledTimes(0);
  105. expect(TestErrorHandlerStrategy.serverErrorSpy.mock.calls[0][0]).toBeInstanceOf(Error);
  106. expect(TestErrorHandlerStrategy.serverErrorSpy.mock.calls[0][0].message).toBe('server error');
  107. expect(TestErrorHandlerStrategy.serverErrorSpy.mock.calls[0][1].host).toBeDefined();
  108. });
  109. it('invokes the worker handler', async () => {
  110. await adminClient.query(
  111. gql`
  112. mutation {
  113. createWorkerError {
  114. id
  115. }
  116. }
  117. `,
  118. );
  119. await awaitRunningJobs(adminClient);
  120. expect(TestErrorHandlerStrategy.serverErrorSpy).toHaveBeenCalledTimes(0);
  121. expect(TestErrorHandlerStrategy.workerErrorSpy).toHaveBeenCalledTimes(1);
  122. expect(TestErrorHandlerStrategy.workerErrorSpy.mock.calls[0][0]).toBeInstanceOf(Error);
  123. expect(TestErrorHandlerStrategy.workerErrorSpy.mock.calls[0][0].message).toBe('worker error');
  124. expect(TestErrorHandlerStrategy.workerErrorSpy.mock.calls[0][1].job).toContain({
  125. queueName: 'test-queue',
  126. });
  127. });
  128. });