1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and 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. /* eslint-disable quotes */
    
  8. 'use strict';
    
  9. 
    
  10. let babel = require('@babel/core');
    
  11. let devExpressionWithCodes = require('../transform-error-messages');
    
  12. 
    
  13. function transform(input, options = {}) {
    
  14.   return babel.transform(input, {
    
  15.     plugins: [[devExpressionWithCodes, options]],
    
  16.   }).code;
    
  17. }
    
  18. 
    
  19. let oldEnv;
    
  20. 
    
  21. describe('error transform', () => {
    
  22.   beforeEach(() => {
    
  23.     oldEnv = process.env.NODE_ENV;
    
  24.     process.env.NODE_ENV = '';
    
  25.   });
    
  26. 
    
  27.   afterEach(() => {
    
  28.     process.env.NODE_ENV = oldEnv;
    
  29.   });
    
  30. 
    
  31.   it('should replace error constructors', () => {
    
  32.     expect(
    
  33.       transform(`
    
  34. new Error('Do not override existing functions.');
    
  35. `)
    
  36.     ).toMatchSnapshot();
    
  37.   });
    
  38. 
    
  39.   it('should replace error constructors (no new)', () => {
    
  40.     expect(
    
  41.       transform(`
    
  42. Error('Do not override existing functions.');
    
  43. `)
    
  44.     ).toMatchSnapshot();
    
  45.   });
    
  46. 
    
  47.   it("should output FIXME for errors that don't have a matching error code", () => {
    
  48.     expect(
    
  49.       transform(`
    
  50. Error('This is not a real error message.');
    
  51. `)
    
  52.     ).toMatchSnapshot();
    
  53.   });
    
  54. 
    
  55.   it(
    
  56.     "should output FIXME for errors that don't have a matching error " +
    
  57.       'code, unless opted out with a comment',
    
  58.     () => {
    
  59.       // TODO: Since this only detects one of many ways to disable a lint
    
  60.       // rule, we should instead search for a custom directive (like
    
  61.       // no-minify-errors) instead of ESLint. Will need to update our lint
    
  62.       // rule to recognize the same directive.
    
  63.       expect(
    
  64.         transform(`
    
  65. // eslint-disable-next-line react-internal/prod-error-codes
    
  66. Error('This is not a real error message.');
    
  67. `)
    
  68.       ).toMatchSnapshot();
    
  69.     }
    
  70.   );
    
  71. 
    
  72.   it('should not touch other calls or new expressions', () => {
    
  73.     expect(
    
  74.       transform(`
    
  75. new NotAnError();
    
  76. NotAnError();
    
  77. `)
    
  78.     ).toMatchSnapshot();
    
  79.   });
    
  80. 
    
  81.   it('should support interpolating arguments with template strings', () => {
    
  82.     expect(
    
  83.       transform(`
    
  84. new Error(\`Expected \${foo} target to be an array; got \${bar}\`);
    
  85. `)
    
  86.     ).toMatchSnapshot();
    
  87.   });
    
  88. 
    
  89.   it('should support interpolating arguments with concatenation', () => {
    
  90.     expect(
    
  91.       transform(`
    
  92. new Error('Expected ' + foo + ' target to be an array; got ' + bar);
    
  93. `)
    
  94.     ).toMatchSnapshot();
    
  95.   });
    
  96. 
    
  97.   it('should support error constructors with concatenated messages', () => {
    
  98.     expect(
    
  99.       transform(`
    
  100. new Error(\`Expected \${foo} target to \` + \`be an array; got \${bar}\`);
    
  101. `)
    
  102.     ).toMatchSnapshot();
    
  103.   });
    
  104. 
    
  105.   it('handles escaped backticks in template string', () => {
    
  106.     expect(
    
  107.       transform(`
    
  108. new Error(\`Expected \\\`\$\{listener\}\\\` listener to be a function, instead got a value of \\\`\$\{type\}\\\` type.\`);
    
  109. `)
    
  110.     ).toMatchSnapshot();
    
  111.   });
    
  112. 
    
  113.   it('handles ignoring errors that are comment-excluded inside ternary expressions', () => {
    
  114.     expect(
    
  115.       transform(`
    
  116. let val = someBool
    
  117.   ? //eslint-disable-next-line react-internal/prod-error-codes
    
  118.     new Error('foo')
    
  119.   : someOtherBool
    
  120.   ? new Error('bar')
    
  121.   : //eslint-disable-next-line react-internal/prod-error-codes
    
  122.     new Error('baz');
    
  123. `)
    
  124.     ).toMatchSnapshot();
    
  125.   });
    
  126. 
    
  127.   it('handles ignoring errors that are comment-excluded outside ternary expressions', () => {
    
  128.     expect(
    
  129.       transform(`
    
  130. //eslint-disable-next-line react-internal/prod-error-codes
    
  131. let val = someBool
    
  132.   ? new Error('foo')
    
  133.   : someOtherBool
    
  134.   ? new Error('bar')
    
  135.   : new Error('baz');
    
  136. `)
    
  137.     ).toMatchSnapshot();
    
  138.   });
    
  139. 
    
  140.   it('handles deeply nested expressions', () => {
    
  141.     expect(
    
  142.       transform(`
    
  143. let val =
    
  144.   (a,
    
  145.   (b,
    
  146.   // eslint-disable-next-line react-internal/prod-error-codes
    
  147.   new Error('foo')));
    
  148. `)
    
  149.     ).toMatchSnapshot();
    
  150. 
    
  151.     expect(
    
  152.       transform(`
    
  153. let val =
    
  154.   (a,
    
  155.   // eslint-disable-next-line react-internal/prod-error-codes
    
  156.   (b, new Error('foo')));
    
  157. `)
    
  158.     ).toMatchSnapshot();
    
  159.   });
    
  160. });