facebook / jscodeshift

A JavaScript codemod toolkit.
https://jscodeshift.com
MIT License
9.32k stars 481 forks source link

Remove test file `.js` requirement in testUtils #336

Open jackbsteinberg opened 5 years ago

jackbsteinberg commented 5 years ago

Currently the runTest function in testUtils.js hardcodes .input.js and .output.js to the test filenames it looks for, which doesn't allow for running test files with .mjs extensions (ES modules).

Can we get a way to run .mjs test files?

jedwards1211 commented 4 years ago

Tbh I think it's not worth it for this project to export test utilities. There's too much variation in how people may want to test transforms (e.g. running a given formatter on the output before comparing it to the expected output). I would recommend just writing your own test utilities, it's not very complicated.

Daniel15 commented 4 years ago

I think this is less of an issue now that the applyTransform method is exported from the test utils (so you can more easily use inline snapshots), and there's also a defineSnapshotTest method.

aneurysmjs commented 3 years ago

Currently the runTest function in testUtils.js hardcodes .input.js and .output.js to the test filenames it looks for, which doesn't allow for running test files with .mjs extensions (ES modules).

Can we get a way to run .mjs test files?

you don't have to worry, inside it just uses 'runInlineTest'

function runTest(dirName, transformName, options, testFilePrefix, testOptions = {}) {
  if (!testFilePrefix) {
    testFilePrefix = transformName;
  }

  const extension = extensionForParser(testOptions.parser)
  const fixtureDir = path.join(dirName, '..', '__testfixtures__');
  const inputPath = path.join(fixtureDir, testFilePrefix + `.input.${extension}`);
  const source = fs.readFileSync(inputPath, 'utf8');
  const expectedOutput = fs.readFileSync(
    path.join(fixtureDir, testFilePrefix + `.output.${extension}`),
    'utf8'
  );
  // Assumes transform is one level up from __tests__ directory
  const module = require(path.join(dirName, '..', transformName));
  runInlineTest(module, options, {
    path: inputPath,
    source
  }, expectedOutput, testOptions);
}
exports.runTest = runTest;

which in turn it just uses 'applyTransform' to do string comparison

function runInlineTest(module, options, input, expectedOutput, testOptions) {
  const output = applyTransform(module, options, input, testOptions);
  expect(output).toEqual(expectedOutput.trim());
  return output;
}

what is doing is detecting whether or not there's a default export aka (ES module) and then calls the transform or in this case your codemode as usual.

function applyTransform(module, options, input, testOptions = {}) {
  // Handle ES6 modules using default export for the transform
  const transform = module.default ? module.default : module;

  // Jest resets the module registry after each test, so we need to always get
  // a fresh copy of jscodeshift on every test run.
  let jscodeshift = require('./core');
  if (testOptions.parser || module.parser) {
    jscodeshift = jscodeshift.withParser(testOptions.parser || module.parser);
  }

  const output = transform(
    input,
    {
      jscodeshift,
      stats: () => {},
    },
    options || {}
  );

  return (output || '').trim();
}

so I think is more easy just to use applyTransform directly and then just do the abstractions you need.

import { applyTransform } from 'jscodeshift/dist/testUtils';

const transformOptions = {};

const actual = 'const arr = []';
const result = `const arr = [{
  name: "Джеро",
  other: aVariable
}]`;

const expected = applyTransform(transform, transformOptions, actual);

test('yeah', () => {
  expect(result).toEqual(expected.trim());
});
danielo515 commented 3 years ago

Why not just finding the files without taking it's extension into consideration? Should not be hard. If you are open to accept it I may create a PR