replaceSandboxedModuleWithDoMock.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. module.exports = function (fileInfo, api) {
  2. const j = api.jscodeshift
  3. const root = j(fileInfo.source)
  4. let shouldAddViImport = false
  5. let shouldRemoveSandboxedModule = false
  6. root
  7. .find(j.CallExpression, {
  8. callee: {
  9. object: { name: 'SandboxedModule' },
  10. property: { name: 'require' },
  11. },
  12. })
  13. .forEach(path => {
  14. shouldRemoveSandboxedModule = true
  15. const args = path.node.arguments
  16. if (args.length > 0) {
  17. const assignmentStatement = path.parentPath.parentPath
  18. const firstArg = args[0]
  19. // Check if there's a second argument with a 'requires' property
  20. if (args.length > 1 && args[1].type === 'ObjectExpression') {
  21. const requiresProp = args[1].properties.find(
  22. prop =>
  23. prop.key.name === 'requires' || prop.key.value === 'requires'
  24. )
  25. if (requiresProp) {
  26. shouldAddViImport = true
  27. const mocks = requiresProp.value.properties.map(mock => {
  28. const depPath =
  29. mock.key.type === 'Literal' ? mock.key.value : mock.key.name
  30. return j.expressionStatement(
  31. j.callExpression(j.identifier('vi.doMock'), [
  32. j.literal(depPath),
  33. j.arrowFunctionExpression(
  34. [],
  35. j.objectExpression([
  36. j.objectProperty(j.identifier('default'), mock.value),
  37. ])
  38. ),
  39. ])
  40. )
  41. })
  42. j(assignmentStatement).insertBefore(mocks)
  43. }
  44. }
  45. // Create an expression to await the import of the module under test
  46. const awaitExpression = j.memberExpression(
  47. j.awaitExpression(
  48. j.callExpression(j.identifier('import'), [firstArg])
  49. ),
  50. j.identifier('default')
  51. )
  52. j(path).replaceWith(awaitExpression)
  53. // Find the closest function and make it async
  54. let functionPath = path
  55. while ((functionPath = functionPath.parent)) {
  56. if (
  57. functionPath.node.type === 'FunctionDeclaration' ||
  58. functionPath.node.type === 'FunctionExpression' ||
  59. functionPath.node.type === 'ArrowFunctionExpression'
  60. ) {
  61. functionPath.node.async = true
  62. break
  63. }
  64. }
  65. }
  66. })
  67. const alreadyHasViImport =
  68. root
  69. .find(j.ImportDeclaration, {
  70. source: { value: 'vitest' },
  71. })
  72. .size() > 0
  73. if (shouldAddViImport && !alreadyHasViImport) {
  74. root
  75. .get()
  76. .node.program.body.unshift(
  77. j.importDeclaration(
  78. [j.importSpecifier(j.identifier('vi'))],
  79. j.literal('vitest')
  80. )
  81. )
  82. }
  83. if (shouldRemoveSandboxedModule) {
  84. root
  85. .find(j.ImportDeclaration, {
  86. source: { value: 'sandboxed-module' },
  87. })
  88. .remove()
  89. }
  90. return root.toSource({
  91. quote: 'single',
  92. })
  93. }