defineTest.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. "use strict";
  2. const fs = require("fs");
  3. const path = require("path");
  4. /**
  5. * Utility function to run a jscodeshift script within a unit test.
  6. * This makes several assumptions about the environment.
  7. *
  8. * Notes:
  9. * - The test should be located in a subdirectory next to the transform itself.
  10. * Commonly tests are located in a directory called __tests__.
  11. *
  12. * - Test data should be located in a directory called __testfixtures__
  13. * alongside the transform and __tests__ directory.
  14. * @param {String} dirName contains the name of the directory the test is located in. This
  15. * should normally be passed via __dirname.
  16. * @param {String} transformName contains the filename of the transform being tested,
  17. * excluding the .js extension.
  18. * @param {String} [testFilePrefix] Optionally contains the name of the file with the test
  19. * data. If not specified, it defaults to the same value as `transformName`.
  20. * This will be suffixed with ".input.js" for the input file and ".output.js"
  21. * for the expected output. For example, if set to "foo", we will read the
  22. * "foo.input.js" file, pass this to the transform, and expect its output to
  23. * be equal to the contents of "foo.output.js".
  24. * @param {Object|Boolean|String} initOptions TBD
  25. * @param {String} action init, update or remove, decides how to format the AST
  26. * @return {Function} Function that fires of the transforms
  27. */
  28. function runSingleTransform(
  29. dirName,
  30. transformName,
  31. testFilePrefix,
  32. initOptions,
  33. action
  34. ) {
  35. if (!testFilePrefix) {
  36. testFilePrefix = transformName;
  37. }
  38. const fixtureDir = path.join(dirName, "__testfixtures__");
  39. const inputPath = path.join(fixtureDir, testFilePrefix + ".input.js");
  40. const source = fs.readFileSync(inputPath, "utf8");
  41. let module;
  42. // Assumes transform and test are on the same level
  43. if (action) {
  44. module = require(path.join(dirName, "index.js"));
  45. } else {
  46. module = require(path.join(dirName, transformName + ".js"));
  47. }
  48. // Handle ES6 modules using default export for the transform
  49. const transform = module.default ? module.default : module;
  50. // Jest resets the module registry after each test, so we need to always get
  51. // a fresh copy of jscodeshift on every test run.
  52. let jscodeshift = require("jscodeshift/dist/core");
  53. if (module.parser) {
  54. jscodeshift = jscodeshift.withParser(module.parser);
  55. }
  56. const ast = jscodeshift(source);
  57. if (initOptions || typeof initOptions === "boolean") {
  58. return transform(
  59. jscodeshift,
  60. ast,
  61. initOptions,
  62. action,
  63. transformName
  64. ).toSource({
  65. quote: "single"
  66. });
  67. }
  68. return transform(jscodeshift, ast, source, action).toSource({
  69. quote: "single"
  70. });
  71. }
  72. /**
  73. * Handles some boilerplate around defining a simple jest/Jasmine test for a
  74. * jscodeshift transform.
  75. * @param {String} dirName contains the name of the directory the test is located in. This
  76. * should normally be passed via __dirname.
  77. * @param {String} transformName contains the filename of the transform being tested,
  78. * excluding the .js extension.
  79. * @param {String} [testFilePrefix] Optionally contains the name of the file with the test
  80. * data. If not specified, it defaults to the same value as `transformName`.
  81. * This will be suffixed with ".input.js" for the input file and ".output.js"
  82. * for the expected output. For example, if set to "foo", we will read the
  83. * "foo.input.js" file, pass this to the transform, and expect its output to
  84. * be equal to the contents of "foo.output.js".
  85. * @param {any} transformObject Object to be transformed with the transformations
  86. * @param {String} action init, update or remove, decides how to format the AST
  87. * @return {Void} Jest makes sure to execute the globally defined functions
  88. */
  89. function defineTest(
  90. dirName,
  91. transformName,
  92. testFilePrefix,
  93. transformObject,
  94. action
  95. ) {
  96. const testName = testFilePrefix
  97. ? `transforms correctly using "${testFilePrefix}" data`
  98. : "transforms correctly";
  99. describe(transformName, () => {
  100. it(testName, () => {
  101. const output = runSingleTransform(
  102. dirName,
  103. transformName,
  104. testFilePrefix,
  105. transformObject,
  106. action
  107. );
  108. expect(output).toMatchSnapshot();
  109. });
  110. });
  111. }
  112. module.exports = defineTest;