GithubHelp home page GithubHelp logo

isabella232 / hermione-codemod Goto Github PK

View Code? Open in Web Editor NEW

This project forked from gemini-testing/hermione-codemod

0.0 0.0 0.0 1 MB

Hermione codemod scripts

License: MIT License

JavaScript 99.79% TypeScript 0.21%

hermione-codemod's Introduction

hermione-codemod Build Status

This repository contains a collection of codemod scripts to be used with JSCodeshift that helps to update Hermione APIs.

Setup & Run

npm install hermione-codemod --save-dev
npx jscodeshift -t <transform> <path> [...options]
  • transform - name of transform script, see available transforms below;
  • path - files or directories that should be transformed (can use glob);
  • options - contains options that passed to the runner of jscodeshift and to the transform script.

For example you can use the -d option for a dry-run and -p to print the output for comparison. The remaining jscodeshift options can be found here.

Included Transforms

browser-chaining-to-async-await

Transforms calls of browser commands from chaining to async-await style. Used in order to update hermione with wdio@7+ inside in which chaining of browser commands does not work anymore and tests should be rewritten to async-await. Moreover in wdio@7 result of calling browser commands does not return to value property anymore, to fix this use remove-browser-prop script.

npx jscodeshift -t hermione-codemod/transforms/browser-chaining-to-async-await.js <path> [...options]

For example (input):

it('test', function() {
  return this.browser
    .foo()
    .bar()
    .then((res) => this.browser.baz(res))
    .qux();
});

will be transformed to (output):

it('test', async function() {
  await this.browser.foo();
  const res = await this.browser.bar();
  await this.browser.baz(res);
  await this.browser.qux();
});

More examples can be found in transforms/__testfixtures__ directory.

Options

  • --browser-name - ability to set used name of browser instance variable in your tests. Transform script will find usage of passed browser names with chaining calls and transform them to await nodes. Default value is browser.

Example:

npx jscodeshift -t <transform> <path> --browser-name='bro1,bro2'

Input:

const fn1 = () => bro1.foo().bar();
const fn2 = () => this.bro2.baz().qux();

Output:

const fn1 = async () => {
  await bro1.foo();
  return bro1.bar();
};
const fn2 = async () => {
  await this.bro2.baz();
  return this.bro2.qux();
};
  • --not-await - ability to set names of called nodes that should not be awaited. For example if you do not await assert calls called inside then callback. Default value is ['assert', 'should', 'expect'].

Example:

npx jscodeshift -t <transform> <path> --not-await='assert,expect'

Input:

(function() {
  return browser.foo()
    .then(() => assert.equal(1, 1))
    .then(() => expect(2).to.equal(2));
})();

Output:

(async function() {
  await browser.foo();
  assert.equal(1, 1);
  return expect(2).to.equal(2);
})();
  • --break-chaining-on - ability to break chaining on nodes that matched to the passed identifiers. For example if you are using chai-as-promised that can be called on browser commands. Default value is ['assert', 'should', 'expect'].

Example:

npx jscodeshift -t <transform> <path> --break-chaining-on='should'

Input:

(function() {
  return browser.foo()
    .should.eventually.equal('foo')
    .bar();
})();

Output:

(async function() {
  await browser.foo();
  static Error("hermione-codemod_1: fix code below manually");
  should.eventually.equal('foo');
  static Error("hermione-codemod_1: fix code above manually");
  await browser.bar();
})();

After that you need to correct the test manually and in the end it might look like this:

(async function() {
  const res = await browser.foo();
  res.should.equal('foo');
  await browser.bar();
})();

Areas of improvement

  • Can't resolve problem with duplication of identifier declaration. Reproduced when parameters of resolve callback inside then have the same name. Currently it should be fixed manually. To simplify the search for such cases, you just need to run transform script again on the same path. Example: Input:
    const fn = () => browser.foo()
      .then((a) => browser.bar(a))
      .then((a) => browser.baz(a));
    Output:
    const fn = async () => {
      const a = await browser.foo();
      const a = await browser.bar(a); // Identifier 'a' has already been declared
      return browser.baz(a);
    };
  • Can't correctly handle the case with call function instead declarate resolve callback in then expression. Currently it should be fixed manually. Example: Input:
    const fn = () => browser.foo().then(bar.bind(browser));
    Output:
    const fn = async () => {
      await browser.foo();
      return bar.bind(browser); // problem: bar function will not be called
    };
    In that case script will inform you about found problem, like this:
    WARN: found CallExpression inside then, maybe you should fix it manually
        file: /your-test.js
        position: {"start":2,"end":2}
    
  • Can't correctly handle the case with usage reject callback in then expression. Currently it should be fixed manually. Example: Input:
    const fn = () => browser.foo().then(() => a(), (err) => b(err));
    Output:
    const fn = async () => {
      await browser.foo();
      return a();
    };
    In that case script will inform you about found problem, like this:
    WARN: can't transform onRejected callback inside "then", fix it manually
        file: /your-test.js
        position: {"start":2,"end":2}
    
  • Can't correctly handle the case with usage catch expression in chaining of browser command calls. Currently it should be fixed manually. Example: Input:
    const fn = () => browser.foo().catch((err) => handle(err));
    Output:
    const fn = async () => {
      await browser.foo();
      return handle(err); // problem: "err" identifier is not declarated
    };
    In that case script will inform you about found problem, like this:
    WARN: can't correctly transform "catch", fix it manually
        file: /your-test.js
        position: {"start":2,"end":2}
    
  • Can't correctly handle the case with usage finally expression in chaining of browser command calls. Currently it should be fixed manually. Example: Input:
    const fn = () => browser.foo().finally(() => doSomething());
    Output:
    const fn = async () => {
      await browser.foo();
      return doSomething(); // problem: should be rewritten with using try - finallly
    };
    In that case script will inform you about found problem, like this:
    WARN: can't correctly transform "finally", fix it manually
        file: /your-test.js
        position: {"start":2,"end":2}
    
  • Can't correctly handle the case with usage logical expression with chaining of browser command calls. Currently it should be fixed manually. Example: Input:
    const fn = () => true && browser.foo().bar();
    Output:
    const fn = async () => true && browser.foo().bar(); // problem: should be rewritten using if statement and await browser commands
    In that case script will inform you about found problem, like this:
    WARN: can't correctly transform LogicalExpression, fix it manually
        file: /your-test.js
        position: {"start":2,"end":2}
    
  • Can't correctly handle the case with usage conditional expression with chaining of browser command calls. Currently it should be fixed manually. Example: Input:
    const fn = () => a ? browser.foo().bar() : b;
    Output:
    const fn = async () => a ? browser.foo().bar() : b; // problem: should be rewritten using if-else statements and await browser commands
    In that case script will inform you about found problem, like this:
    WARN: can't correctly transform ConditionalExpression, fix it manually
        file: undefined
        position: {"start":2,"end":2}
    

Example of usage

  1. Run transform script on files that should be modified. For example I want modify all files inside tests/platform/** whose name matches on *.hermione.js or *.hermione-helper.js:
npx jscodeshift -t node_modules/hermione-codemod/transforms/browser-chaining-to-async-await.js tests/platform/**/*.*(hermione|hermione-helper).js --not-await='assert'
  1. After transformation of all tests script may inform you about found problems which are listed above, fix them manually.
  2. Run transform script again even if it does not inform you about any problems in previous step. It is necessary because it can found problems with duplication of identifier declaration after transformation code. Rerun transform script until it succeeds and won't inform you that no test has been modified.
  3. Fix code style in trasformed tests:
npx eslint --fix tests/platform/**/*.*(hermione|hermione-helper).js

remove-browser-prop

Removes usages of the passed property from the result of calling browser commands. Used in order to update hermione with wdio@7+ inside in which property value not used anymore for store result of executing browser command. Must be used only after browser-chaining-to-async-await script.

npx jscodeshift -t node_modules/hermione-codemod/transforms/remove-browser-prop.js <path> [...options]

For example (input):

it('test', async function() {
  const res1 = await this.browser.foo();
  const {value: res2} = await this.browser.bar();
  const res3 = (await this.browser.baz()).value;

  return [res1.value, res2, res3]
});

will be transformed to (output):

it('test', async function() {
  const res1 = await this.browser.foo();
  const res2 = await this.browser.bar();
  const res3 = await this.browser.baz();

  return [res1, res2, res3];
});

More examples can be found in transforms/__testfixtures__ directory.

Options

  • --browser-name - as like in browser-chaining-to-async-await script;

  • --property-name - ability to set name of property which should be removed from the result of calling browser commands. Default value is value.

    Example:

    npx jscodeshift -t <transform> <path> --property-name='value'

Recast Options

Options to recast's printer can be provided through the printOptions command line argument.

npx jscodeshift -t <transform> <path> --printOptions='{"tabWidth":2}'

hermione-codemod's People

Contributors

dudagod avatar sipayrt avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.