mocksGraphqlPlugin.js 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/
  2. /* eslint-disable no-nested-ternary */
  3. /* eslint-disable @typescript-eslint/no-require-imports */
  4. const { basename } = require('path')
  5. const { convertFactory } = require('@graphql-codegen/visitor-plugin-common')
  6. const camelCase = require('lodash/camelCase.js')
  7. const startCase = require('lodash/startCase.js')
  8. /* eslint-enable @typescript-eslint/no-require-imports */
  9. /** @typedef {import('graphql').OperationDefinitionNode} OperationDefinitionNode */
  10. const pascalCase = (str) => startCase(camelCase(str))
  11. const getCompositionFunctionSuffix = (name, operationType) => {
  12. if (
  13. name.includes('Query') ||
  14. name.includes('Mutation') ||
  15. name.includes('Subscription')
  16. ) {
  17. return ''
  18. }
  19. return pascalCase(operationType)
  20. }
  21. const getOperationSuffix = (config, node, operationType) => {
  22. const { omitOperationSuffix = false, dedupeOperationSuffix = false } = config
  23. const operationName =
  24. typeof node === 'string' ? node : node.name ? node.name.value : ''
  25. return omitOperationSuffix
  26. ? ''
  27. : dedupeOperationSuffix &&
  28. operationName.toLowerCase().endsWith(operationType.toLowerCase())
  29. ? ''
  30. : operationType
  31. }
  32. module.exports.plugin = (schema, documents, config) => {
  33. // we assume that there is only one operation per file
  34. // if not, then we take the first operation and assume it is the only one
  35. const node = documents[0].document.definitions[0]
  36. const suffix = getCompositionFunctionSuffix(node.name.value, node.operation)
  37. const convertName = convertFactory(config)
  38. const operationName = convertName(node.name.value, {
  39. suffix,
  40. useTypesPrefix: false,
  41. })
  42. const baseFile = basename(documents[0].location).replace(
  43. /\.graphql$/,
  44. '.api.ts',
  45. )
  46. const documentVariableName = convertName(node, {
  47. suffix: config.documentVariableSuffix || 'Document',
  48. prefix: config.documentVariablePrefix,
  49. useTypesPrefix: false,
  50. })
  51. const operationType = pascalCase(node.operation)
  52. const operationTypeSuffix = getOperationSuffix(config, node, operationType)
  53. const operationResultType = `Types.${convertName(node, {
  54. suffix: operationTypeSuffix,
  55. })}`
  56. const operationVariablesTypes = `Types.${convertName(node, {
  57. suffix: `${operationTypeSuffix}Variables`,
  58. })}`
  59. return {
  60. prepend: [
  61. "import * as Mocks from '#tests/graphql/builders/mocks.ts'",
  62. `import * as Operations from './${baseFile}'`,
  63. "import * as ErrorTypes from '#shared/types/error.ts'",
  64. ],
  65. content: [
  66. node.operation === 'subscription'
  67. ? `
  68. export function get${operationName}Handler() {
  69. return Mocks.getGraphQLSubscriptionHandler<${operationResultType}>(Operations.${documentVariableName})
  70. }
  71. `
  72. : `
  73. export function mock${operationName}(defaults: Mocks.MockDefaultsValue<${operationResultType}, ${operationVariablesTypes}>) {
  74. return Mocks.mockGraphQLResult(Operations.${documentVariableName}, defaults)
  75. }
  76. export function waitFor${operationName}Calls() {
  77. return Mocks.waitForGraphQLMockCalls<${operationResultType}>(Operations.${documentVariableName})
  78. }
  79. export function mock${operationName}Error(message: string, extensions: {type: ErrorTypes.GraphQLErrorTypes }) {
  80. return Mocks.mockGraphQLResultWithError(Operations.${documentVariableName}, message, extensions);
  81. }
  82. `,
  83. ],
  84. }
  85. }