runPrettier.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. "use strict";
  2. const fs = require("fs");
  3. const path = require("path");
  4. const stripAnsi = require("strip-ansi");
  5. const isProduction = process.env.NODE_ENV === "production";
  6. const prettierRootDir = isProduction ? process.env.PRETTIER_DIR : "../";
  7. const prettierPkg = require(path.join(prettierRootDir, "package.json"));
  8. const prettierCli = path.join(prettierRootDir, prettierPkg.bin.prettier);
  9. const thirdParty = isProduction
  10. ? path.join(prettierRootDir, "./third-party")
  11. : path.join(prettierRootDir, "./src/common/third-party");
  12. function runPrettier(dir, args, options) {
  13. args = args || [];
  14. options = options || {};
  15. let status;
  16. let stdout = "";
  17. let stderr = "";
  18. jest.spyOn(process, "exit").mockImplementation(exitCode => {
  19. if (status === undefined) {
  20. status = exitCode || 0;
  21. }
  22. });
  23. jest
  24. .spyOn(process.stdout, "write")
  25. .mockImplementation(text => appendStdout(text));
  26. jest
  27. .spyOn(process.stderr, "write")
  28. .mockImplementation(text => appendStderr(text));
  29. jest
  30. .spyOn(console, "log")
  31. .mockImplementation(text => appendStdout(text + "\n"));
  32. jest
  33. .spyOn(console, "warn")
  34. .mockImplementation(text => appendStderr(text + "\n"));
  35. jest
  36. .spyOn(console, "error")
  37. .mockImplementation(text => appendStderr(text + "\n"));
  38. jest.spyOn(Date, "now").mockImplementation(() => 0);
  39. const write = [];
  40. jest.spyOn(fs, "writeFileSync").mockImplementation((filename, content) => {
  41. write.push({ filename, content });
  42. });
  43. const originalCwd = process.cwd();
  44. const originalArgv = process.argv;
  45. const originalExitCode = process.exitCode;
  46. const originalStdinIsTTY = process.stdin.isTTY;
  47. const originalStdoutIsTTY = process.stdout.isTTY;
  48. process.chdir(normalizeDir(dir));
  49. process.stdin.isTTY = !!options.isTTY;
  50. process.stdout.isTTY = !!options.stdoutIsTTY;
  51. process.argv = ["path/to/node", "path/to/prettier/bin"].concat(args);
  52. jest.resetModules();
  53. // We cannot use `jest.setMock("get-stream", impl)` here, because in the
  54. // production build everything is bundled into one file so there is no
  55. // "get-stream" module to mock.
  56. jest.spyOn(require(thirdParty), "getStream").mockImplementation(() => ({
  57. then: handler => handler(options.input || "")
  58. }));
  59. jest
  60. .spyOn(require(thirdParty), "cosmiconfig")
  61. .mockImplementation((moduleName, options) =>
  62. require("cosmiconfig")(
  63. moduleName,
  64. Object.assign({}, options, { stopDir: __dirname })
  65. )
  66. );
  67. jest
  68. .spyOn(require(thirdParty), "findParentDir")
  69. .mockImplementation(() => process.cwd());
  70. try {
  71. require(prettierCli);
  72. status = (status === undefined ? process.exitCode : status) || 0;
  73. } catch (error) {
  74. status = 1;
  75. stderr += error.message;
  76. } finally {
  77. process.chdir(originalCwd);
  78. process.argv = originalArgv;
  79. process.exitCode = originalExitCode;
  80. process.stdin.isTTY = originalStdinIsTTY;
  81. process.stdout.isTTY = originalStdoutIsTTY;
  82. jest.restoreAllMocks();
  83. }
  84. const result = { status, stdout, stderr, write };
  85. const testResult = testOptions => {
  86. testOptions = testOptions || {};
  87. Object.keys(result).forEach(name => {
  88. test(`(${name})`, () => {
  89. const value =
  90. typeof result[name] === "string"
  91. ? stripAnsi(result[name])
  92. : result[name];
  93. if (name in testOptions) {
  94. if (name === "status" && testOptions[name] === "non-zero") {
  95. expect(value).not.toEqual(0);
  96. } else {
  97. expect(value).toEqual(testOptions[name]);
  98. }
  99. } else {
  100. expect(value).toMatchSnapshot();
  101. }
  102. });
  103. });
  104. return result;
  105. };
  106. return Object.assign({ test: testResult }, result);
  107. function appendStdout(text) {
  108. if (status === undefined) {
  109. stdout += text;
  110. }
  111. }
  112. function appendStderr(text) {
  113. if (status === undefined) {
  114. stderr += text;
  115. }
  116. }
  117. }
  118. function normalizeDir(dir) {
  119. const isRelative = dir[0] !== "/";
  120. return isRelative ? path.resolve(__dirname, dir) : dir;
  121. }
  122. module.exports = runPrettier;