testUtils.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /**
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. /* global expect, describe, it */
  8. 'use strict';
  9. const fs = require('fs');
  10. const path = require('path');
  11. function applyTransform(module, options, input, testOptions = {}) {
  12. // Handle ES6 modules using default export for the transform
  13. const transform = module.default ? module.default : module;
  14. // Jest resets the module registry after each test, so we need to always get
  15. // a fresh copy of jscodeshift on every test run.
  16. let jscodeshift = require('./core');
  17. if (testOptions.parser || module.parser) {
  18. jscodeshift = jscodeshift.withParser(testOptions.parser || module.parser);
  19. }
  20. const output = transform(
  21. input,
  22. {
  23. jscodeshift,
  24. stats: () => {},
  25. },
  26. options || {}
  27. );
  28. return (output || '').trim();
  29. }
  30. exports.applyTransform = applyTransform;
  31. function runSnapshotTest(module, options, input) {
  32. const output = applyTransform(module, options, input);
  33. expect(output).toMatchSnapshot();
  34. return output;
  35. }
  36. exports.runSnapshotTest = runSnapshotTest;
  37. function runInlineTest(module, options, input, expectedOutput, testOptions) {
  38. const output = applyTransform(module, options, input, testOptions);
  39. expect(output).toEqual(expectedOutput.trim());
  40. return output;
  41. }
  42. exports.runInlineTest = runInlineTest;
  43. function extensionForParser(parser) {
  44. switch (parser) {
  45. case 'ts':
  46. case 'tsx':
  47. return parser;
  48. default:
  49. return 'js'
  50. }
  51. }
  52. /**
  53. * Utility function to run a jscodeshift script within a unit test. This makes
  54. * several assumptions about the environment:
  55. *
  56. * - `dirName` contains the name of the directory the test is located in. This
  57. * should normally be passed via __dirname.
  58. * - The test should be located in a subdirectory next to the transform itself.
  59. * Commonly tests are located in a directory called __tests__.
  60. * - `transformName` contains the filename of the transform being tested,
  61. * excluding the .js extension.
  62. * - `testFilePrefix` optionally contains the name of the file with the test
  63. * data. If not specified, it defaults to the same value as `transformName`.
  64. * This will be suffixed with ".input.js" for the input file and ".output.js"
  65. * for the expected output. For example, if set to "foo", we will read the
  66. * "foo.input.js" file, pass this to the transform, and expect its output to
  67. * be equal to the contents of "foo.output.js".
  68. * - Test data should be located in a directory called __testfixtures__
  69. * alongside the transform and __tests__ directory.
  70. */
  71. function runTest(dirName, transformName, options, testFilePrefix, testOptions = {}) {
  72. if (!testFilePrefix) {
  73. testFilePrefix = transformName;
  74. }
  75. const extension = extensionForParser(testOptions.parser)
  76. const fixtureDir = path.join(dirName, '..', '__testfixtures__');
  77. const inputPath = path.join(fixtureDir, testFilePrefix + `.input.${extension}`);
  78. const source = fs.readFileSync(inputPath, 'utf8');
  79. const expectedOutput = fs.readFileSync(
  80. path.join(fixtureDir, testFilePrefix + `.output.${extension}`),
  81. 'utf8'
  82. );
  83. // Assumes transform is one level up from __tests__ directory
  84. const module = require(path.join(dirName, '..', transformName));
  85. runInlineTest(module, options, {
  86. path: inputPath,
  87. source
  88. }, expectedOutput, testOptions);
  89. }
  90. exports.runTest = runTest;
  91. /**
  92. * Handles some boilerplate around defining a simple jest/Jasmine test for a
  93. * jscodeshift transform.
  94. */
  95. function defineTest(dirName, transformName, options, testFilePrefix, testOptions) {
  96. const testName = testFilePrefix
  97. ? `transforms correctly using "${testFilePrefix}" data`
  98. : 'transforms correctly';
  99. describe(transformName, () => {
  100. it(testName, () => {
  101. runTest(dirName, transformName, options, testFilePrefix, testOptions);
  102. });
  103. });
  104. }
  105. exports.defineTest = defineTest;
  106. function defineInlineTest(module, options, input, expectedOutput, testName) {
  107. it(testName || 'transforms correctly', () => {
  108. runInlineTest(module, options, {
  109. source: input
  110. }, expectedOutput);
  111. });
  112. }
  113. exports.defineInlineTest = defineInlineTest;
  114. function defineSnapshotTest(module, options, input, testName) {
  115. it(testName || 'transforms correctly', () => {
  116. runSnapshotTest(module, options, {
  117. source: input
  118. });
  119. });
  120. }
  121. exports.defineSnapshotTest = defineSnapshotTest;