├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .npmignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── RELEASE.md ├── appveyor.yml ├── bin └── cli.js ├── package.json ├── transforms ├── -preset.js ├── .gitkeep ├── acceptance │ ├── README.md │ ├── __testfixtures__ │ │ ├── andthen.input.js │ │ ├── andthen.output.js │ │ ├── attr.input.js │ │ ├── attr.output.js │ │ ├── click.input.js │ │ ├── click.output.js │ │ ├── each.input.js │ │ ├── each.output.js │ │ ├── fill-in.input.js │ │ ├── fill-in.output.js │ │ ├── get-value.input.js │ │ ├── get-value.output.js │ │ ├── get.input.js │ │ ├── get.output.js │ │ ├── has-class.input.js │ │ ├── has-class.output.js │ │ ├── html.input.js │ │ ├── html.output.js │ │ ├── key-event.input.js │ │ ├── key-event.output.js │ │ ├── length.input.js │ │ ├── length.output.js │ │ ├── nested-in-and-then.input.js │ │ ├── nested-in-and-then.output.js │ │ ├── prop.input.js │ │ ├── prop.output.js │ │ ├── route-helpers.input.js │ │ ├── route-helpers.output.js │ │ ├── selected.input.js │ │ ├── selected.output.js │ │ ├── text.input.js │ │ ├── text.output.js │ │ ├── trigger-event.input.js │ │ ├── trigger-event.output.js │ │ ├── visit.input.js │ │ └── visit.output.js │ ├── index.js │ ├── test.js │ └── transforms │ │ ├── attr.js │ │ ├── click.js │ │ ├── each.js │ │ ├── fill-in.js │ │ ├── get-value.js │ │ ├── get.js │ │ ├── has-class.js │ │ ├── html.js │ │ ├── key-event.js │ │ ├── length.js │ │ ├── prop.js │ │ ├── route-helpers.js │ │ ├── tail-eq.js │ │ ├── text.js │ │ ├── trigger-event.js │ │ └── visit.js ├── ember-test-helper-api-migration │ ├── README.md │ ├── __testfixtures__ │ │ ├── basic.input.js │ │ ├── basic.output.js │ │ ├── do-not-have-@ember-test-helpers-import.input.js │ │ ├── do-not-have-@ember-test-helpers-import.output.js │ │ ├── do-not-have-ember-test-helpers-import.input.js │ │ └── do-not-have-ember-test-helpers-import.output.js │ ├── index.js │ └── test.js ├── find │ ├── README.md │ ├── __testfixtures__ │ │ ├── find.input.js │ │ └── find.output.js │ ├── index.js │ └── test.js ├── integration │ ├── README.md │ ├── __testfixtures__ │ │ ├── all.input.js │ │ ├── all.output.js │ │ ├── attr.input.js │ │ ├── attr.output.js │ │ ├── click.input.js │ │ ├── click.output.js │ │ ├── default-component-test.input.js │ │ ├── default-component-test.output.js │ │ ├── each.input.js │ │ ├── each.output.js │ │ ├── event.input.js │ │ ├── event.output.js │ │ ├── focus.input.js │ │ ├── focus.output.js │ │ ├── get-value.input.js │ │ ├── get-value.output.js │ │ ├── get.input.js │ │ ├── get.output.js │ │ ├── has-class.input.js │ │ ├── has-class.output.js │ │ ├── html.input.js │ │ ├── html.output.js │ │ ├── jq-extensions.input.js │ │ ├── jq-extensions.output.js │ │ ├── key-event.input.js │ │ ├── key-event.output.js │ │ ├── length.input.js │ │ ├── length.output.js │ │ ├── prop.input.js │ │ ├── prop.output.js │ │ ├── selected.input.js │ │ ├── selected.output.js │ │ ├── set-value.input.js │ │ ├── set-value.output.js │ │ ├── text.input.js │ │ ├── text.output.js │ │ ├── typescript.input.ts │ │ └── typescript.output.ts │ ├── index.js │ ├── test.js │ └── transforms │ │ ├── attr.js │ │ ├── click.js │ │ ├── each.js │ │ ├── focus.js │ │ ├── get-value.js │ │ ├── get.js │ │ ├── has-class.js │ │ ├── html.js │ │ ├── key-event.js │ │ ├── length.js │ │ ├── prop.js │ │ ├── set-value.js │ │ ├── text.js │ │ ├── trigger-shortcut.js │ │ └── trigger.js ├── native-dom │ ├── README.md │ ├── __testfixtures__ │ │ ├── acceptance.input.js │ │ ├── acceptance.output.js │ │ ├── context-argument.input.js │ │ ├── context-argument.output.js │ │ ├── double-import.input.js │ │ ├── double-import.output.js │ │ ├── integration.input.js │ │ ├── integration.output.js │ │ ├── prune-import.input.js │ │ └── prune-import.output.js │ ├── index.js │ └── test.js ├── this-render-migration │ ├── README.md │ ├── __testfixtures__ │ │ ├── basic.input.js │ │ ├── basic.output.js │ │ ├── has-no-ember-test-helpers-import.input.js │ │ └── has-no-ember-test-helpers-import.output.js │ ├── index.js │ └── test.js ├── update-triggerevent-file-param │ ├── README.md │ ├── __testfixtures__ │ │ ├── basic.input.js │ │ └── basic.output.js │ ├── index.js │ └── test.js └── utils.js └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | !.* 2 | __testfixtures__ -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parserOptions: { 3 | ecmaVersion: 2018, 4 | }, 5 | 6 | plugins: ['prettier', 'node'], 7 | extends: ['eslint:recommended', 'plugin:prettier/recommended', 'plugin:node/recommended'], 8 | env: { 9 | node: true, 10 | }, 11 | rules: {}, 12 | overrides: [ 13 | { 14 | files: ['__tests__/**/*.js'], 15 | env: { 16 | jest: true, 17 | }, 18 | }, 19 | ], 20 | }; 21 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - 'v*' # older version branches 8 | tags: 9 | - '*' 10 | pull_request: {} 11 | schedule: 12 | - cron: '0 6 * * 0' # weekly, on sundays 13 | 14 | jobs: 15 | lint: 16 | name: Linting 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - uses: actions/checkout@v1 21 | - uses: actions/setup-node@v1 22 | with: 23 | node-version: 12.x 24 | - name: install yarn 25 | run: npm install -g yarn 26 | - name: install dependencies 27 | run: yarn install 28 | - name: linting 29 | run: yarn lint 30 | 31 | test: 32 | name: Tests 33 | runs-on: ubuntu-latest 34 | 35 | strategy: 36 | matrix: 37 | node: ['10', '12'] 38 | 39 | steps: 40 | - uses: actions/checkout@v1 41 | - uses: actions/setup-node@v1 42 | with: 43 | node-version: ${{ matrix.node }} 44 | - name: install yarn 45 | run: npm install --global yarn 46 | - name: install dependencies 47 | run: yarn 48 | - name: test 49 | run: yarn test 50 | 51 | floating-test: 52 | name: Floating dependencies 53 | runs-on: ubuntu-latest 54 | 55 | steps: 56 | - uses: actions/checkout@v1 57 | - uses: actions/setup-node@v1 58 | with: 59 | node-version: '12.x' 60 | - name: install yarn 61 | run: npm install -g yarn 62 | - name: install dependencies 63 | run: yarn install --no-lockfile 64 | - name: test 65 | run: yarn test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /.eslintcache -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "es5", 4 | "printWidth": 100 5 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v0.3.1 (2021-03-10) 2 | 3 | #### :rocket: Enhancement 4 | * [#46](https://github.com/ember-codemods/ember-test-helpers-codemod/pull/46) add `update-triggerevent-file-param` transform ([@zhanwang626](https://github.com/zhanwang626)) 5 | 6 | #### Committers: 1 7 | - Zhan Wang ([@zhanwang626](https://github.com/zhanwang626)) 8 | 9 | ## v0.3.0 (2021-03-02) 10 | 11 | #### :boom: Breaking Change 12 | * [#45](https://github.com/ember-codemods/ember-test-helpers-codemod/pull/45) Update codemod-cli and boilerplate, drop node 6 +8 ([@simonihmig](https://github.com/simonihmig)) 13 | 14 | #### :rocket: Enhancement 15 | * [#42](https://github.com/ember-codemods/ember-test-helpers-codemod/pull/42) add transform for migrating deprecated ember-test-helpers API ([@zhanwang626](https://github.com/zhanwang626)) 16 | * [#43](https://github.com/ember-codemods/ember-test-helpers-codemod/pull/43) add transform to replace deprecated this.render() ([@zhanwang626](https://github.com/zhanwang626)) 17 | 18 | #### :bug: Bug Fix 19 | * [#41](https://github.com/ember-codemods/ember-test-helpers-codemod/pull/41) Text content fix ([@fivetanley](https://github.com/fivetanley)) 20 | 21 | #### :house: Internal 22 | * [#44](https://github.com/ember-codemods/ember-test-helpers-codemod/pull/44) Setup release-it ([@simonihmig](https://github.com/simonihmig)) 23 | * [#45](https://github.com/ember-codemods/ember-test-helpers-codemod/pull/45) Update codemod-cli and boilerplate, drop node 6 +8 ([@simonihmig](https://github.com/simonihmig)) 24 | 25 | #### Committers: 4 26 | - Eli Flanagan ([@efx](https://github.com/efx)) 27 | - Simon Ihmig ([@simonihmig](https://github.com/simonihmig)) 28 | - Stanley Stuart ([@fivetanley](https://github.com/fivetanley)) 29 | - Zhan Wang ([@zhanwang626](https://github.com/zhanwang626)) 30 | 31 | # Changelog 32 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ember-test-helpers-codemod 2 | 3 | [![Build Status](https://travis-ci.org/ember-codemods/ember-test-helpers-codemod.svg?branch=master)](https://travis-ci.org/ember-codemods/ember-test-helpers-codemod) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/fadn7iu9fl53qb6k/branch/master?svg=true)](https://ci.appveyor.com/project/simonihmig/ember-test-helpers-codemod/branch/master) 5 | [![npm version](https://badge.fury.io/js/ember-test-helpers-codemod.svg)](https://badge.fury.io/js/ember-test-helpers-codemod) 6 | 7 | A [jscodeshift](https://github.com/facebook/jscodeshift) based codemod to help migrating your jQuery or 8 | `ember-native-dom-helpers` based Ember tests to [`@ember/test-helpers`](https://github.com/emberjs/ember-test-helpers). 9 | 10 | *Please note that this will not be able to cover all possible cases how jQuery based tests can be written. 11 | Given the dynamic nature of JavaScript and the extensive API and fluent interface of jQuery, this would be impossible. 12 | Instead this codemod focuses to cover the most common usages and do those transformations that it can safely do. 13 | So it is likely that you will have to manually migrate some usages this tool cannot cover!* 14 | 15 | ## Usage 16 | 17 | **WARNING**: `jscodeshift`, and thus this codemod, **edits your files in place**. 18 | It does not make a copy. Make sure your code is checked into a source control 19 | repository like Git and that you have no outstanding changes to commit before 20 | running this tool. 21 | 22 | ```bash 23 | cd my-ember-app-or-addon 24 | npx ember-test-helpers-codemod integration tests/integration 25 | npx ember-test-helpers-codemod acceptance tests/acceptance 26 | npx ember-test-helpers-codemod native-dom tests 27 | ``` 28 | 29 | ## Transformations 30 | 31 | ### Integration tests 32 | 33 | This addon will perform the following transformations suitable for integration tests: 34 | 35 | | Before | After | Transform | 36 | |------------------------------------------------------|-----------------------------------------------------------------------|----------------| 37 | | `this.$('.foo').attr('id')` | `find('.foo').id` | `attr.js` | 38 | | `this.$('.foo').attr('data-test')` | `find('.foo').getAttribute('data-test')` | `attr.js` | 39 | | `this.$('.foo').click()` | `await click('.foo')` | `click.js` | 40 | | `this.$('.foo').change()` (and more events) | `await triggerEvent('.foo', 'change')` | `trigger-shortcut.js` | 41 | | `this.$('.foo').trigger('input')` | `await triggerEvent('.foo', 'input')` | `trigger.js` | 42 | | `this.$('.foo').focus()` | `await focus('.foo')` | `focus.js` | 43 | | `this.$('.foo').val()` | `find('.foo').value` | `get-value.js` | 44 | | `this.$('div').hasClass('foo')` | `find('div').classList.contains('foo')` | `has-class.js` | 45 | | `this.$('.foo').trigger('click')` | `await click('.foo')` | `key-event.js` | 46 | | `this.$('.foo').trigger('keydown', { keyCode: 13 })` | `await keyEvent('.foo', 'keydown', 13)` | `key-event.js` | 47 | | `this.$('.foo').length` | `findAll('.foo').length` | `length.js` | 48 | | `this.$('.foo').prop('tagName')` | `find('.foo').tagName` | `prop.js` | 49 | | `this.$('.foo').val('foo')` | `await fillIn('.foo', 'foo')` | `set-value.js` | 50 | | `this.$('.foo').val('bar').change()` | `await fillIn('.foo', 'foo'); await blur('.foo');` | `set-value.js` | 51 | | `this.$('.foo').val('bar').trigger('input')` | `await fillIn('.foo', 'foo')` | `set-value.js` | 52 | | `this.$('.foo').text()` | `find('.foo').textContent` | `text.js` | 53 | | `this.$('.foo').html()` | `find('.foo').innerHTML` | `html.js` | 54 | | `this.$('.foo').html('foo')` | `find('.foo').innerHTML = 'foo'` | `html.js` | 55 | | `this.$('.foo').each((index, elem) => {...})` | `findAll('.foo').forEach((elem, index) => {...})` | `each.js` | 56 | | `this.$('.foo').get(3)` | `findAll('.foo')[3]` | `get.js` | 57 | 58 | 59 | If you want to run only selected transforms on your code, you can pick just the needed transform: 60 | 61 | ```bash 62 | jscodeshift -t path/to/ember-test-helpers-codemod/transforms/integration/transforms/click.js tests/integration 63 | ``` 64 | 65 | See also docs for [`integration` transform](transforms/integration). 66 | 67 | ### Acceptance tests 68 | 69 | These transformations are available for acceptance tests: 70 | 71 | | Before | After | Transform | 72 | |------------------------------------------------------|-----------------------------------------------------------------------|----------------| 73 | | `find('.foo').attr('id')` | `find('.foo').id` | `attr.js` | 74 | | `find('.foo').attr('data-test')` | `find('.foo').getAttribute('data-test')` | `attr.js` | 75 | | `click('.foo')` | `await click('.foo')` | `click.js` | 76 | | `fillIn('#bar', 'baz')` | `await fillIn('#bar', 'baz')` | `fill-in.js` | 77 | | `triggerEvent('input', 'focus')` | `await focus('.foo')` | `trigger-event.js` | 78 | | `triggerEvent('input', 'blur')` | `await blur('.foo')` | `trigger-event.js` | 79 | | `triggerEvent('input', 'mouseenter')` | `await triggerEvent('input', 'mouseenter')` | `trigger-event.js` | 80 | | `find('.foo').val()` | `find('.foo').value` | `get-value.js` | 81 | | `find('div').hasClass('foo')` | `find('div').classList.contains('foo')` | `has-class.js` | 82 | | `keyEvent('#bar', 'keypress', 13);` | `await keyEvent('.foo', 'keydown', 13)` | `key-event.js` | 83 | | `find('.foo').length` | `findAll('.foo').length` | `length.js` | 84 | | `find('.foo').prop('tagName')` | `find('.foo').tagName` | `prop.js` | 85 | | `find('.foo').text()` | `find('.foo').textContent` | `text.js` | 86 | | `find('.foo').html()` | `find('.foo').innerHTML` | `html.js` | 87 | | `find('.foo').html('foo')` | `find('.foo').innerHTML = 'foo'` | `html.js` | 88 | | `find('.foo').each((index, elem) => {...})` | `findAll('.foo').forEach((elem, index) => {...})` | `each.js` | 89 | | `find('.foo').get(3)` | `findAll('.foo')[3]` | `get.js` | 90 | 91 | If you want to run only selected transforms on your code, you can pick just the needed transform: 92 | 93 | ```bash 94 | jscodeshift -t ../ember-test-helpers-codemod/transforms/acceptance/transforms/click.js tests/integration 95 | ``` 96 | 97 | See also docs for [`acceptance` transform](transforms/acceptance). 98 | 99 | ### ember-native-dom-helpers tests 100 | 101 | These transformations are available for tests based on `ember-native-dom-helpers`: 102 | 103 | | Before | After | Transform | 104 | |---------------------------------------|-------------------------|----------------| 105 | | ```import { click, find, findAll, fillIn, focus, blur, triggerEvent, keyEvent, waitFor, waitUntil } from 'ember-native-dom-helpers';``` | ```import { click, find, findAll, fillIn, focus, blur, triggerEvent, triggerKeyEvent, waitFor, waitUntil } from '@ember/test-helpers';``` | 106 | | `find('.foo', context)` | `context.querySelector('.foo')` | 107 | | `find('.foo', '.context')` | `find('.context .foo')` | 108 | | `findAll('.foo', context)` | `context.querySelectorAll('.foo')` | 109 | | `click('.foo', context)` | `click(context.querySelector('.foo'))` | 110 | | `click('.foo', context, { shiftKey: true })` | `click(context.querySelector('.foo'), { shiftKey: true })` | 111 | 112 | See also docs for [`native-dom` transform](transforms/native-dom). 113 | 114 | ### Replace find/findAll 115 | 116 | By default this codemod will use the `find()` and `findAll()` helpers from `@ember/test-helpers` where required. 117 | If you want to use the native query functions `this.element.querySelector()` / `this.element.querySelectorAll()` instead, 118 | you can use the `find.js` transform after you have run the other transformations: 119 | 120 | ```bash 121 | npx ember-test-helpers-codemod find tests 122 | ``` 123 | 124 | | Before | After | Transform | 125 | |----------------------|-----------------------------------------|----------------| 126 | | `find('.foo')` | `this.element.querySelector('.foo')` | `find.js` | 127 | | `findAll('.foo')` | `this.element.querySelectorAll('.foo')` | `find.js` | 128 | 129 | Note that this will require all instances of `find`/`findAll` to have the correct `this` context, otherwise you will run 130 | into `Cannot read property 'querySelector' of undefined` exceptions, as `this.element` will not be defined. This can 131 | happen outside of the main `test` function, for example inside of custom test helper functions. 132 | 133 | See also docs for [`find` transform](transforms/find). 134 | 135 | ### Replace deprecated `ember-test-helpers` package 136 | 137 | Replace all imports of `ember-test-helpers` to `@ember/test-helpers`. 138 | 139 | See docs for [`ember-test-helper-api-migration` transform](transforms/ember-test-helper-api-migration). 140 | 141 | ### Replace deprecated `this.render()` with `render()` 142 | 143 | Replace all uses of `this.render()` with `render()`. 144 | 145 | See docs for [`this-render-migration` transform](transforms/this-render-migration). -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | Releases are mostly automated using 4 | [release-it](https://github.com/release-it/release-it/) and 5 | [lerna-changelog](https://github.com/lerna/lerna-changelog/). 6 | 7 | ## Preparation 8 | 9 | Since the majority of the actual release process is automated, the primary 10 | remaining task prior to releasing is confirming that all pull requests that 11 | have been merged since the last release have been labeled with the appropriate 12 | `lerna-changelog` labels and the titles have been updated to ensure they 13 | represent something that would make sense to our users. Some great information 14 | on why this is important can be found at 15 | [keepachangelog.com](https://keepachangelog.com/en/1.0.0/), but the overall 16 | guiding principle here is that changelogs are for humans, not machines. 17 | 18 | When reviewing merged PR's the labels to be used are: 19 | 20 | * breaking - Used when the PR is considered a breaking change. 21 | * enhancement - Used when the PR adds a new feature or enhancement. 22 | * bug - Used when the PR fixes a bug included in a previous release. 23 | * documentation - Used when the PR adds or updates documentation. 24 | * internal - Used for internal changes that still require a mention in the 25 | changelog/release notes. 26 | 27 | ## Release 28 | 29 | Once the prep work is completed, the actual release is straight forward: 30 | 31 | * First, ensure that you have installed your projects dependencies: 32 | 33 | ```sh 34 | yarn install 35 | ``` 36 | 37 | * Second, ensure that you have obtained a 38 | [GitHub personal access token][generate-token] with the `repo` scope (no 39 | other permissions are needed). Make sure the token is available as the 40 | `GITHUB_AUTH` environment variable. 41 | 42 | For instance: 43 | 44 | ```bash 45 | export GITHUB_AUTH=abc123def456 46 | ``` 47 | 48 | [generate-token]: https://github.com/settings/tokens/new?scopes=repo&description=GITHUB_AUTH+env+variable 49 | 50 | * And last (but not least 😁) do your release. 51 | 52 | ```sh 53 | npx release-it 54 | ``` 55 | 56 | [release-it](https://github.com/release-it/release-it/) manages the actual 57 | release process. It will prompt you to to choose the version number after which 58 | you will have the chance to hand tweak the changelog to be used (for the 59 | `CHANGELOG.md` and GitHub release), then `release-it` continues on to tagging, 60 | pushing the tag and commits, etc. 61 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: "6" 4 | - nodejs_version: "8" 5 | 6 | # Fix line endings in Windows. (runs before repo cloning) 7 | init: 8 | - git config --global core.autocrlf true 9 | 10 | # Install scripts. (runs after repo cloning) 11 | install: 12 | - ps: Install-Product node $env:nodejs_version 13 | - appveyor-retry yarn 14 | 15 | # Post-install test scripts. 16 | test_script: 17 | - node --version 18 | - yarn test 19 | 20 | # http://help.appveyor.com/discussions/questions/1310-delete-cache 21 | cache: 22 | - '%LOCALAPPDATA%\Yarn' 23 | 24 | # Don't actually build. 25 | build: off -------------------------------------------------------------------------------- /bin/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | require('codemod-cli').runTransform( 5 | __dirname, 6 | process.argv[2] /* transform name */, 7 | process.argv.slice(3) /* paths or globs */ 8 | ); 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-test-helpers-codemod", 3 | "version": "0.3.1", 4 | "description": "Codemod to transform your jQuery based ember tests to use @ember/test-helpers", 5 | "keywords": [ 6 | "codemod-cli" 7 | ], 8 | "repository": "https://github.com/simonihmig/ember-test-helpers-codemod", 9 | "license": "MIT", 10 | "author": "Simon Ihmig ", 11 | "main": "index.js", 12 | "bin": "./bin/cli.js", 13 | "scripts": { 14 | "lint": "eslint --cache .", 15 | "test": "codemod-cli test", 16 | "test:coverage": "codemod-cli test --coverage", 17 | "update-docs": "codemod-cli update-docs", 18 | "coveralls": "cat ./coverage/lcov.info | node node_modules/.bin/coveralls" 19 | }, 20 | "jest": { 21 | "testEnvironment": "node" 22 | }, 23 | "dependencies": { 24 | "codemod-cli": "^2.1.0" 25 | }, 26 | "devDependencies": { 27 | "coveralls": "^3.0.6", 28 | "eslint": "^7.21.0", 29 | "eslint-config-prettier": "^8.1.0", 30 | "eslint-plugin-node": "^11.1.0", 31 | "eslint-plugin-prettier": "^3.3.1", 32 | "jest": "^24.9.0", 33 | "prettier": "^2.2.1", 34 | "release-it": "^14.2.1", 35 | "release-it-lerna-changelog": "^3.1.0" 36 | }, 37 | "engines": { 38 | "node": "10.* || >= 12" 39 | }, 40 | "publishConfig": { 41 | "registry": "https://registry.npmjs.org" 42 | }, 43 | "release-it": { 44 | "plugins": { 45 | "release-it-lerna-changelog": { 46 | "infile": "CHANGELOG.md", 47 | "launchEditor": true 48 | } 49 | }, 50 | "git": { 51 | "tagName": "v${version}" 52 | }, 53 | "github": { 54 | "release": true, 55 | "tokenRef": "GITHUB_AUTH" 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /transforms/-preset.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const fs = require('fs'); 5 | 6 | module.exports = function (type) { 7 | let transformPath = path.join(__dirname, type, 'transforms'); 8 | 9 | return function (file, api, options) { 10 | let src = file.source; 11 | let error; 12 | 13 | fs.readdirSync(transformPath).forEach((fileName) => { 14 | let fix = require(path.join(transformPath, fileName)); 15 | if (typeof src === 'undefined') { 16 | return; 17 | } 18 | try { 19 | src = fix(Object.assign({}, file, { source: src }), api, options); 20 | } catch (e) { 21 | error = new Error( 22 | `Transformation ${fileName} errored on file ${file.path}. Reason ${e}. Please report this in https://github.com/simonihmig/ember-test-helpers-codemod/issues\n\nStack trace:\n${e.stack}\n\nSource:\n${src}` 23 | ); 24 | } 25 | }); 26 | 27 | if (error) { 28 | throw error; 29 | } 30 | return src; 31 | }; 32 | }; 33 | -------------------------------------------------------------------------------- /transforms/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-codemods/ember-test-helpers-codemod/d25c1edb4eba9e0545ce9b758422a54326872e5a/transforms/.gitkeep -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/andthen.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('click'); 5 | 6 | test('visiting /foo', function(assert) { 7 | visit('/foo'); 8 | andThen(function() { 9 | }); 10 | 11 | andThen(function() { 12 | assert.ok(true); 13 | }); 14 | }); 15 | 16 | test('visiting /foo', function(assert) { 17 | visit('/foo'); 18 | return andThen(function() { 19 | }); 20 | }); 21 | 22 | test('visiting /foo', function(assert) { 23 | visit('/foo'); 24 | return andThen(function() { 25 | assert.ok(true); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/andthen.output.js: -------------------------------------------------------------------------------- 1 | import { visit } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('click'); 6 | 7 | test('visiting /foo', async function(assert) { 8 | await visit('/foo'); 9 | assert.ok(true); 10 | }); 11 | 12 | test('visiting /foo', async function(assert) { 13 | await visit('/foo'); 14 | }); 15 | 16 | test('visiting /foo', async function(assert) { 17 | await visit('/foo'); 18 | assert.ok(true); 19 | }); 20 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/attr.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('find'); 5 | 6 | test('visiting /foo', function(assert) { 7 | assert.equal(find('.foo').attr('id'), 'foo'); 8 | assert.equal(find('.foo').attr('data-test'), 'foo'); 9 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/attr.output.js: -------------------------------------------------------------------------------- 1 | import { find } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('find'); 6 | 7 | test('visiting /foo', function(assert) { 8 | assert.equal(find('.foo').id, 'foo'); 9 | assert.equal(find('.foo').getAttribute('data-test'), 'foo'); 10 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/click.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('click'); 5 | 6 | test('visiting /foo', function(assert) { 7 | visit('/foo'); 8 | 9 | click('#bar'); 10 | click('.baz a:eq(12)'); 11 | andThen(function() { 12 | assert.equal(currentURL(), '/foo'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/click.output.js: -------------------------------------------------------------------------------- 1 | import { click, currentURL, findAll, visit } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('click'); 6 | 7 | test('visiting /foo', async function(assert) { 8 | await visit('/foo'); 9 | 10 | await click('#bar'); 11 | await click(findAll('.baz a')[12]); 12 | assert.equal(currentURL(), '/foo'); 13 | }); 14 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/each.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('find'); 5 | 6 | test('anonymous function callback with two args', function(assert) { 7 | const elemIds = find('.button-class').each((index, element) => { 8 | assert.equal(element.id, `button${index}`); 9 | }); 10 | }); 11 | 12 | test('anonymous function callback with one arg', function(assert) { 13 | const elemIds = find('.button-class').each((index) => { 14 | assert.equal(element.id, `button${index}`); 15 | }); 16 | }); 17 | 18 | test('function callback with two args', function(assert) { 19 | const elemIds = find('.button-class').each(function(i, elem) { 20 | assert.equal(element.id, `button${index}`); 21 | }); 22 | }); 23 | 24 | test('function callback with one arg', function(assert) { 25 | const elemIds = find('.button-class').each((index) => { 26 | assert.equal(element.id, `button${index}`); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/each.output.js: -------------------------------------------------------------------------------- 1 | import { findAll } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('find'); 6 | 7 | test('anonymous function callback with two args', function(assert) { 8 | const elemIds = findAll('.button-class').forEach((element, index) => { 9 | assert.equal(element.id, `button${index}`); 10 | }); 11 | }); 12 | 13 | test('anonymous function callback with one arg', function(assert) { 14 | const elemIds = findAll('.button-class').forEach((element, index) => { 15 | assert.equal(element.id, `button${index}`); 16 | }); 17 | }); 18 | 19 | test('function callback with two args', function(assert) { 20 | const elemIds = findAll('.button-class').forEach(function(elem, i) { 21 | assert.equal(element.id, `button${index}`); 22 | }); 23 | }); 24 | 25 | test('function callback with one arg', function(assert) { 26 | const elemIds = findAll('.button-class').forEach((element, index) => { 27 | assert.equal(element.id, `button${index}`); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/fill-in.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('fillIn'); 5 | 6 | test('visiting /foo', function(assert) { 7 | visit('/foo'); 8 | 9 | fillIn('#bar', 'baz'); 10 | fillIn('#qux input:eq(5)', 'qaaz'); 11 | andThen(function() { 12 | assert.equal(currentURL(), '/foo'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/fill-in.output.js: -------------------------------------------------------------------------------- 1 | import { fillIn, currentURL, findAll, visit } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('fillIn'); 6 | 7 | test('visiting /foo', async function(assert) { 8 | await visit('/foo'); 9 | 10 | await fillIn('#bar', 'baz'); 11 | await fillIn(findAll('#qux input')[5], 'qaaz'); 12 | assert.equal(currentURL(), '/foo'); 13 | }); 14 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/get-value.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('find'); 5 | 6 | test('visiting /foo', function(assert) { 7 | assert.equal(find('.foo').val(), 'foo'); 8 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/get-value.output.js: -------------------------------------------------------------------------------- 1 | import { find } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('find'); 6 | 7 | test('visiting /foo', function(assert) { 8 | assert.equal(find('.foo').value, 'foo'); 9 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/get.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('get'); 5 | 6 | test('transforms get() correctly', function(assert) { 7 | assert.ok(find('.foo bar').get(3)); 8 | 9 | const otherGet = someOtherObj.get(1); 10 | }); 11 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/get.output.js: -------------------------------------------------------------------------------- 1 | import { findAll } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('get'); 6 | 7 | test('transforms get() correctly', function(assert) { 8 | assert.ok(findAll('.foo bar')[3]); 9 | 10 | const otherGet = someOtherObj.get(1); 11 | }); 12 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/has-class.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('find'); 5 | 6 | test('visiting /foo', function(assert) { 7 | assert.ok(find('.foo').hasClass('foo')); 8 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/has-class.output.js: -------------------------------------------------------------------------------- 1 | import { find } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('find'); 6 | 7 | test('visiting /foo', function(assert) { 8 | assert.ok(find('.foo').classList.contains('foo')); 9 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/html.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('find'); 5 | 6 | test('visiting /foo', function(assert) { 7 | assert.equal(find('.foo').html().trim(), ''); 8 | 9 | find('.foo').html('bar'); 10 | 11 | assert.equal(find('.foo').html().trim(), 'bar'); 12 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/html.output.js: -------------------------------------------------------------------------------- 1 | import { find } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('find'); 6 | 7 | test('visiting /foo', function(assert) { 8 | assert.equal(find('.foo').innerHTML.trim(), ''); 9 | 10 | find('.foo').innerHTML = 'bar'; 11 | 12 | assert.equal(find('.foo').innerHTML.trim(), 'bar'); 13 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/key-event.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('keyEvent'); 5 | 6 | test('visiting /foo', function(assert) { 7 | visit('/foo'); 8 | 9 | keyEvent('#bar', 'keypress', 13); 10 | andThen(function() { 11 | assert.equal(currentURL(), '/foo'); 12 | }); 13 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/key-event.output.js: -------------------------------------------------------------------------------- 1 | import { keyEvent, currentURL, visit } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('keyEvent'); 6 | 7 | test('visiting /foo', async function(assert) { 8 | await visit('/foo'); 9 | 10 | await keyEvent('#bar', 'keypress', 13); 11 | assert.equal(currentURL(), '/foo'); 12 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/length.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('find'); 5 | 6 | test('visiting /foo', function(assert) { 7 | assert.equal(find('.foo').length, 1); 8 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/length.output.js: -------------------------------------------------------------------------------- 1 | import { findAll } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('find'); 6 | 7 | test('visiting /foo', function(assert) { 8 | assert.equal(findAll('.foo').length, 1); 9 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/nested-in-and-then.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('find'); 5 | 6 | test('visiting /twiddles', function(assert) { 7 | andThen(function() { 8 | click('.foo'); 9 | }); 10 | 11 | andThen(() => { 12 | click('.foo'); 13 | }); 14 | 15 | andThen(function() { 16 | andThen(function() { 17 | andThen(function() { 18 | click('.foo'); 19 | }); 20 | }); 21 | }); 22 | 23 | andThen(() => { 24 | assert.ok(true); 25 | }); 26 | 27 | andThen(() => assert.ok(true)); 28 | }); 29 | 30 | test('visiting /twiddles', function(assert) { 31 | andThen(() => { 32 | click('.foo'); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/nested-in-and-then.output.js: -------------------------------------------------------------------------------- 1 | import { click } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('find'); 6 | 7 | test('visiting /twiddles', async function(assert) { 8 | await click('.foo'); 9 | 10 | await click('.foo'); 11 | 12 | await click('.foo'); 13 | 14 | assert.ok(true); 15 | 16 | assert.ok(true); 17 | }); 18 | 19 | test('visiting /twiddles', async function(assert) { 20 | await click('.foo'); 21 | }); 22 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/prop.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('find'); 5 | 6 | test('visiting /foo', function(assert) { 7 | assert.equal(find('.foo').prop('tagName'), 'DIV'); 8 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/prop.output.js: -------------------------------------------------------------------------------- 1 | import { find } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('find'); 6 | 7 | test('visiting /foo', function(assert) { 8 | assert.equal(find('.foo').tagName, 'DIV'); 9 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/route-helpers.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('click'); 5 | 6 | test('visiting /foo', function(assert) { 7 | visit('/foo'); 8 | assert.equal(currentURL(), '/foo'); 9 | assert.equal(currentPath(), 'foo.index'); 10 | assert.equal(currentRouteName(), 'foo'); 11 | }); 12 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/route-helpers.output.js: -------------------------------------------------------------------------------- 1 | import { currentURL, currentPath, currentRouteName, visit } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('click'); 6 | 7 | test('visiting /foo', async function(assert) { 8 | await visit('/foo'); 9 | assert.equal(currentURL(), '/foo'); 10 | assert.equal(currentPath(), 'foo.index'); 11 | assert.equal(currentRouteName(), 'foo'); 12 | }); 13 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/selected.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('selected'); 5 | 6 | test(':selected is replaced correctly', function(assert) { 7 | // find 8 | const checkedVal = find('.foo input:selected').val(); 9 | assert.equal(checkedVal, 13); 10 | 11 | // findAll 12 | const checkedCount = find('select option:selected').length; 13 | assert.equal(checkedCount, 3); 14 | }); 15 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/selected.output.js: -------------------------------------------------------------------------------- 1 | import { find, findAll } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('selected'); 6 | 7 | test(':selected is replaced correctly', function(assert) { 8 | // find 9 | const checkedVal = find('.foo input:checked').value; 10 | assert.equal(checkedVal, 13); 11 | 12 | // findAll 13 | const checkedCount = findAll('select option:checked').length; 14 | assert.equal(checkedCount, 3); 15 | }); 16 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/text.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('find'); 5 | 6 | test('visiting /foo', function(assert) { 7 | assert.equal(find('.foo').text().trim(), ''); 8 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/text.output.js: -------------------------------------------------------------------------------- 1 | import { find } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('find'); 6 | 7 | test('visiting /foo', function(assert) { 8 | assert.equal(find('.foo').textContent.trim(), ''); 9 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/trigger-event.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('triggerEvent'); 5 | 6 | test('visiting /foo', function(assert) { 7 | visit('/foo'); 8 | 9 | triggerEvent('input', 'focus'); 10 | triggerEvent('input', 'blur'); 11 | triggerEvent('#bar', 'mouseenter'); 12 | andThen(function() { 13 | assert.equal(currentURL(), '/foo'); 14 | }); 15 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/trigger-event.output.js: -------------------------------------------------------------------------------- 1 | import { currentURL, blur, focus, triggerEvent, visit } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('triggerEvent'); 6 | 7 | test('visiting /foo', async function(assert) { 8 | await visit('/foo'); 9 | 10 | await focus('input'); 11 | await blur('input'); 12 | await triggerEvent('#bar', 'mouseenter'); 13 | assert.equal(currentURL(), '/foo'); 14 | }); -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/visit.input.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('click'); 5 | 6 | test('visiting /foo', function(assert) { 7 | visit('/foo'); 8 | andThen(function() { 9 | assert.equal(currentURL(), '/foo'); 10 | }); 11 | }); 12 | 13 | test('visiting /bar', function(assert) { 14 | visit('/bar'); 15 | andThen(() => { 16 | assert.equal(currentURL(), '/bar'); 17 | }); 18 | }); 19 | 20 | test('visiting /bar', async function(assert) { 21 | await visit('/bar'); 22 | assert.equal(currentURL(), '/bar'); 23 | }); 24 | 25 | test('visiting /bar', async function(assert) { 26 | await assert.rejects(visit('/bar')); 27 | assert.equal(currentURL(), '/bar'); 28 | }); 29 | -------------------------------------------------------------------------------- /transforms/acceptance/__testfixtures__/visit.output.js: -------------------------------------------------------------------------------- 1 | import { currentURL, visit } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('click'); 6 | 7 | test('visiting /foo', async function(assert) { 8 | await visit('/foo'); 9 | assert.equal(currentURL(), '/foo'); 10 | }); 11 | 12 | test('visiting /bar', async function(assert) { 13 | await visit('/bar'); 14 | assert.equal(currentURL(), '/bar'); 15 | }); 16 | 17 | test('visiting /bar', async function(assert) { 18 | await visit('/bar'); 19 | assert.equal(currentURL(), '/bar'); 20 | }); 21 | 22 | test('visiting /bar', async function(assert) { 23 | await assert.rejects(visit('/bar')); 24 | assert.equal(currentURL(), '/bar'); 25 | }); 26 | -------------------------------------------------------------------------------- /transforms/acceptance/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const preset = require('../-preset'); 4 | 5 | module.exports = preset('acceptance'); 6 | -------------------------------------------------------------------------------- /transforms/acceptance/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { runTransformTest } = require('codemod-cli'); 4 | 5 | runTransformTest({ 6 | type: 'jscodeshift', 7 | name: 'acceptance', 8 | }); 9 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/attr.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindExpression, 6 | createPropExpression, 7 | isFindExpression, 8 | addImportStatement, 9 | writeImportStatements, 10 | } = require('../../utils'); 11 | 12 | /** 13 | * Creates a `find(selector).getAttribute(attr)` expression 14 | * 15 | * @param j 16 | * @param findArgs 17 | * @param attr 18 | * @returns {*} 19 | */ 20 | function createAttributeExpression(j, findArgs, attr) { 21 | return j.callExpression( 22 | j.memberExpression(createFindExpression(j, findArgs), j.identifier('getAttribute')), 23 | [attr] 24 | ); 25 | } 26 | 27 | /** 28 | * Check if `node` is a `this.$(selector).attr('foo')` expression 29 | * 30 | * @param j 31 | * @param node 32 | * @returns {*|boolean} 33 | */ 34 | function isJQueryExpression(j, node) { 35 | return ( 36 | j.CallExpression.check(node) && 37 | j.MemberExpression.check(node.callee) && 38 | isFindExpression(j, node.callee.object) && 39 | j.Identifier.check(node.callee.property) && 40 | node.callee.property.name === 'attr' && 41 | node.arguments.length === 1 42 | ); 43 | } 44 | /** 45 | * Should we translate this to a `.getAttribute('foo')` or a `.foo` expression? 46 | * 47 | * @param j 48 | * @param node 49 | * @returns {*|boolean} 50 | */ 51 | function isPropertyAccessPreferred(j, node) { 52 | let arg = node.arguments[0]; 53 | return j.Literal.check(arg) && arg.value === 'id'; 54 | } 55 | 56 | /** 57 | * Transform `this.$(selector).attr('foo')` to `find(selector).getAttribute(attr)` 58 | * 59 | * @param file 60 | * @param api 61 | * @returns {*|string} 62 | */ 63 | function transform(file, api) { 64 | let source = file.source; 65 | let j = getParser(api); 66 | 67 | let root = j(source); 68 | 69 | let propReplacements = root 70 | .find(j.CallExpression) 71 | .filter(({ node }) => isJQueryExpression(j, node)) 72 | .filter(({ node }) => isPropertyAccessPreferred(j, node)) 73 | .replaceWith(({ node }) => 74 | createPropExpression(j, node.callee.object.arguments, node.arguments[0].value) 75 | ); 76 | 77 | let attrReplacements = root 78 | .find(j.CallExpression) 79 | .filter(({ node }) => isJQueryExpression(j, node)) 80 | .filter(({ node }) => !isPropertyAccessPreferred(j, node)) 81 | .replaceWith(({ node }) => 82 | createAttributeExpression(j, node.callee.object.arguments, node.arguments[0]) 83 | ); 84 | 85 | if (propReplacements.length > 0 || attrReplacements.length > 0) { 86 | addImportStatement(['find']); 87 | } 88 | 89 | writeImportStatements(j, root); 90 | return root.toSource({ quote: 'single' }); 91 | } 92 | 93 | module.exports = transform; 94 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/click.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | makeAwait, 6 | dropAndThen, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Check if `node` is a `click(selector)` expression 13 | * 14 | * @param j 15 | * @param node 16 | * @returns {*|boolean} 17 | */ 18 | function isGlobalHelperExpression(j, node) { 19 | return ( 20 | j.CallExpression.check(node) && j.Identifier.check(node.callee) && node.callee.name === 'click' 21 | ); 22 | } 23 | 24 | /** 25 | * Transform `click(selector)` to `await click(selector)`, remove `andThen` calls 26 | * 27 | * @param file 28 | * @param api 29 | * @returns {*|string} 30 | */ 31 | function transform(file, api) { 32 | let source = file.source; 33 | let j = getParser(api); 34 | 35 | let root = j(source); 36 | 37 | let replacements = root 38 | .find(j.CallExpression) 39 | .filter(({ node }) => isGlobalHelperExpression(j, node)); 40 | if (replacements.length > 0) { 41 | makeAwait(j, replacements); 42 | dropAndThen(j, root); 43 | addImportStatement(['click']); 44 | } 45 | 46 | writeImportStatements(j, root); 47 | return root.toSource({ quote: 'single' }); 48 | } 49 | 50 | module.exports = transform; 51 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/each.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindAllExpression, 6 | isFindExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | transformEachsCallbackArgs, 10 | } = require('../../utils'); 11 | 12 | /** 13 | * Creates a `findAll(selector).forEach()` expression 14 | * 15 | * @param j 16 | * @param findArgs 17 | * @param eachCallback 18 | * @returns {*} 19 | */ 20 | function createExpression(j, findArgs, eachCallback) { 21 | const transformedCallback = transformEachsCallbackArgs(eachCallback); 22 | return j.callExpression( 23 | j.memberExpression(createFindAllExpression(j, findArgs), j.identifier('forEach')), 24 | transformedCallback 25 | ); 26 | } 27 | 28 | /** 29 | * Check if `node` is a `find(selector).each()` expression 30 | * 31 | * @param j 32 | * @param node 33 | * @returns {*|boolean} 34 | */ 35 | function isJQueryExpression(j, node) { 36 | return ( 37 | j.CallExpression.check(node) && 38 | j.MemberExpression.check(node.callee) && 39 | isFindExpression(j, node.callee.object) && 40 | j.Identifier.check(node.callee.property) && 41 | node.callee.property.name === 'each' 42 | ); 43 | } 44 | 45 | /** 46 | * Transform `find(selector).each()` to `findAll(selector).forEach()` 47 | * 48 | * @param file 49 | * @param api 50 | * @returns {*|string} 51 | */ 52 | function transform(file, api) { 53 | let source = file.source; 54 | let j = getParser(api); 55 | 56 | let root = j(source); 57 | 58 | let replacements = root 59 | .find(j.CallExpression) 60 | .filter(({ node }) => isJQueryExpression(j, node)) 61 | .replaceWith(({ node }) => createExpression(j, node.callee.object.arguments, node.arguments)); 62 | 63 | if (replacements.length > 0) { 64 | addImportStatement(['findAll']); 65 | } 66 | 67 | writeImportStatements(j, root); 68 | return root.toSource({ quote: 'single' }); 69 | } 70 | 71 | module.exports = transform; 72 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/fill-in.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | makeAwait, 6 | dropAndThen, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Check if `node` is a `fillIn(selector)` expression 13 | * 14 | * @param j 15 | * @param node 16 | * @returns {*|boolean} 17 | */ 18 | function isGlobalHelperExpression(j, node) { 19 | return ( 20 | j.CallExpression.check(node) && j.Identifier.check(node.callee) && node.callee.name === 'fillIn' 21 | ); 22 | } 23 | 24 | /** 25 | * Transform `fillIn(selector)` to `await fillIn(selector)`, remove `andThen` calls 26 | * 27 | * @param file 28 | * @param api 29 | * @returns {*|string} 30 | */ 31 | function transform(file, api) { 32 | let source = file.source; 33 | let j = getParser(api); 34 | 35 | let root = j(source); 36 | 37 | let replacements = root 38 | .find(j.CallExpression) 39 | .filter(({ node }) => isGlobalHelperExpression(j, node)); 40 | if (replacements.length > 0) { 41 | makeAwait(j, replacements); 42 | dropAndThen(j, root); 43 | addImportStatement(['fillIn']); 44 | } 45 | 46 | writeImportStatements(j, root); 47 | return root.toSource({ quote: 'single' }); 48 | } 49 | 50 | module.exports = transform; 51 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/get-value.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindExpression, 6 | isFindExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Creates a `find(selector).value` expression 13 | * 14 | * @param j 15 | * @param findArgs 16 | * @returns {*} 17 | */ 18 | function createExpression(j, findArgs) { 19 | return j.memberExpression(createFindExpression(j, findArgs), j.identifier('value')); 20 | } 21 | 22 | /** 23 | * Check if `node` is a `this.$(selector).val()` expression 24 | * 25 | * @param j 26 | * @param node 27 | * @returns {*|boolean} 28 | */ 29 | function isJQueryExpression(j, node) { 30 | return ( 31 | j.CallExpression.check(node) && 32 | j.MemberExpression.check(node.callee) && 33 | isFindExpression(j, node.callee.object) && 34 | j.Identifier.check(node.callee.property) && 35 | node.callee.property.name === 'val' && 36 | node.arguments.length === 0 37 | ); 38 | } 39 | 40 | /** 41 | * Transform `this.$(selector).val()` to `find(selector).value` 42 | * 43 | * @param file 44 | * @param api 45 | * @returns {*|string} 46 | */ 47 | function transform(file, api) { 48 | let source = file.source; 49 | let j = getParser(api); 50 | 51 | let root = j(source); 52 | 53 | let replacements = root 54 | .find(j.CallExpression) 55 | .filter(({ node }) => isJQueryExpression(j, node)) 56 | .replaceWith(({ node }) => createExpression(j, node.callee.object.arguments)); 57 | 58 | if (replacements.length > 0) { 59 | addImportStatement(['find']); 60 | } 61 | 62 | writeImportStatements(j, root); 63 | return root.toSource({ quote: 'single' }); 64 | } 65 | 66 | module.exports = transform; 67 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/get.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindAllExpression, 6 | isFindExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Creates a `findAll(selector)[0]` expression 13 | * 14 | * @param j 15 | * @param findArgs 16 | * @param indexArg 17 | * @returns {*} 18 | */ 19 | function createExpression(j, findArgs, indexArg) { 20 | const index = (indexArg[0] && indexArg[0].value) || 0; 21 | return j.memberExpression(createFindAllExpression(j, findArgs), j.literal(index)); 22 | } 23 | 24 | /** 25 | * Check if `node` is a `find(selector).get(0)` expression 26 | * 27 | * @param j 28 | * @param node 29 | * @returns {*|boolean} 30 | */ 31 | function isJQueryExpression(j, node) { 32 | return ( 33 | j.CallExpression.check(node) && 34 | j.MemberExpression.check(node.callee) && 35 | isFindExpression(j, node.callee.object) && 36 | j.Identifier.check(node.callee.property) && 37 | node.callee.property.name === 'get' 38 | ); 39 | } 40 | 41 | /** 42 | * Transform `find(selector).get(0)` to `findAll(selector)[0]` 43 | * 44 | * @param file 45 | * @param api 46 | * @returns {*|string} 47 | */ 48 | function transform(file, api) { 49 | let source = file.source; 50 | let j = getParser(api); 51 | 52 | let root = j(source); 53 | 54 | let replacements = root 55 | .find(j.CallExpression) 56 | .filter(({ node }) => isJQueryExpression(j, node)) 57 | .replaceWith(({ node }) => createExpression(j, node.callee.object.arguments, node.arguments)); 58 | 59 | if (replacements.length > 0) { 60 | addImportStatement(['findAll']); 61 | } 62 | 63 | writeImportStatements(j, root); 64 | return root.toSource({ quote: 'single' }); 65 | } 66 | 67 | module.exports = transform; 68 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/has-class.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindExpression, 6 | isFindExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Creates a `find(selector).classList.contains(className)` expression 13 | * 14 | * @param j 15 | * @param findArgs 16 | * @param className 17 | * @returns {*} 18 | */ 19 | function createExpression(j, findArgs, className) { 20 | return j.callExpression( 21 | j.memberExpression( 22 | j.memberExpression(createFindExpression(j, findArgs), j.identifier('classList')), 23 | j.identifier('contains') 24 | ), 25 | [className] 26 | ); 27 | } 28 | 29 | /** 30 | * Check if `node` is a `this.$(selector).hasClass(className)` expression 31 | * 32 | * @param j 33 | * @param node 34 | * @returns {*|boolean} 35 | */ 36 | function isJQueryExpression(j, node) { 37 | return ( 38 | j.CallExpression.check(node) && 39 | j.MemberExpression.check(node.callee) && 40 | isFindExpression(j, node.callee.object) && 41 | j.Identifier.check(node.callee.property) && 42 | node.callee.property.name === 'hasClass' 43 | ); 44 | } 45 | 46 | /** 47 | * Transform `this.$(selector).hasClass(className)` to `find(selector)classList.contains(className)` 48 | * 49 | * @param file 50 | * @param api 51 | * @returns {*|string} 52 | */ 53 | function transform(file, api) { 54 | let source = file.source; 55 | let j = getParser(api); 56 | 57 | let root = j(source); 58 | 59 | let replacements = root 60 | .find(j.CallExpression) 61 | .filter(({ node }) => isJQueryExpression(j, node)) 62 | .replaceWith(({ node }) => 63 | createExpression(j, node.callee.object.arguments, node.arguments[0]) 64 | ); 65 | 66 | if (replacements.length > 0) { 67 | addImportStatement(['find']); 68 | } 69 | 70 | writeImportStatements(j, root); 71 | return root.toSource({ quote: 'single' }); 72 | } 73 | 74 | module.exports = transform; 75 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/html.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindExpression, 6 | isFindExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Creates a `find(selector).innerHTML` expression 13 | * 14 | * @param j 15 | * @param findArgs 16 | * @param attr 17 | * @returns {*} 18 | */ 19 | function createExpression(j, node) { 20 | let findArgs = node.callee.object.arguments; 21 | let findExpression = j.memberExpression( 22 | createFindExpression(j, findArgs), 23 | j.identifier('innerHTML') 24 | ); 25 | 26 | if (node.arguments.length === 0) { 27 | return findExpression; 28 | } else { 29 | return j.assignmentExpression('=', findExpression, node.arguments[0]); 30 | } 31 | } 32 | 33 | /** 34 | * Check if `node` is a `this.$(selector).html()` expression 35 | * 36 | * @param j 37 | * @param node 38 | * @returns {*|boolean} 39 | */ 40 | function isJQueryExpression(j, node) { 41 | return ( 42 | j.CallExpression.check(node) && 43 | j.MemberExpression.check(node.callee) && 44 | isFindExpression(j, node.callee.object) && 45 | j.Identifier.check(node.callee.property) && 46 | node.callee.property.name === 'html' 47 | ); 48 | } 49 | 50 | /** 51 | * Transform `this.$(selector).html()` to `find(selector).innerHTML` 52 | * 53 | * @param file 54 | * @param api 55 | * @returns {*|string} 56 | */ 57 | function transform(file, api) { 58 | let source = file.source; 59 | let j = getParser(api); 60 | 61 | let root = j(source); 62 | 63 | let replacements = root 64 | .find(j.CallExpression) 65 | .filter(({ node }) => isJQueryExpression(j, node)) 66 | .replaceWith(({ node }) => createExpression(j, node)); 67 | 68 | if (replacements.length > 0) { 69 | addImportStatement(['find']); 70 | } 71 | 72 | writeImportStatements(j, root); 73 | return root.toSource({ quote: 'single' }); 74 | } 75 | 76 | module.exports = transform; 77 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/key-event.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | makeAwait, 6 | dropAndThen, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Check if `node` is a `keyEvent(...)` expression 13 | * 14 | * @param j 15 | * @param node 16 | * @returns {*|boolean} 17 | */ 18 | function isGlobalHelperExpression(j, node) { 19 | return ( 20 | j.CallExpression.check(node) && 21 | j.Identifier.check(node.callee) && 22 | node.callee.name === 'keyEvent' 23 | ); 24 | } 25 | 26 | /** 27 | * Transform `keyEvent(...)` to `await keyEvent(...)`, remove `andThen` calls 28 | * 29 | * @param file 30 | * @param api 31 | * @returns {*|string} 32 | */ 33 | function transform(file, api) { 34 | let source = file.source; 35 | let j = getParser(api); 36 | 37 | let root = j(source); 38 | 39 | let replacements = root 40 | .find(j.CallExpression) 41 | .filter(({ node }) => isGlobalHelperExpression(j, node)); 42 | if (replacements.length > 0) { 43 | makeAwait(j, replacements); 44 | dropAndThen(j, root); 45 | addImportStatement(['keyEvent']); 46 | } 47 | 48 | writeImportStatements(j, root); 49 | return root.toSource({ quote: 'single' }); 50 | } 51 | 52 | module.exports = transform; 53 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/length.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindAllExpression, 6 | isFindExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Creates a `findAll(selector).length` expression 13 | * 14 | * @param j 15 | * @param findArgs 16 | * @returns {*} 17 | */ 18 | function createExpression(j, findArgs) { 19 | return j.memberExpression(createFindAllExpression(j, findArgs), j.identifier('length')); 20 | } 21 | 22 | /** 23 | * Check if `node` is a `this.$(selector).length` expression 24 | * 25 | * @param j 26 | * @param node 27 | * @returns {*|boolean} 28 | */ 29 | function isJQueryExpression(j, node) { 30 | return ( 31 | j.MemberExpression.check(node) && 32 | isFindExpression(j, node.object) && 33 | j.Identifier.check(node.property) && 34 | node.property.name === 'length' 35 | ); 36 | } 37 | 38 | /** 39 | * Transforms `this.$(selector).length` to `findAll(selector).length` 40 | * 41 | * @param file 42 | * @param api 43 | * @returns {*|string} 44 | */ 45 | function transform(file, api) { 46 | let source = file.source; 47 | let j = getParser(api); 48 | 49 | let root = j(source); 50 | 51 | let replacements = root 52 | .find(j.MemberExpression) 53 | .filter(({ node }) => isJQueryExpression(j, node)) 54 | .replaceWith(({ node }) => createExpression(j, node.object.arguments)); 55 | 56 | if (replacements.length > 0) { 57 | addImportStatement(['findAll']); 58 | } 59 | 60 | writeImportStatements(j, root); 61 | return root.toSource({ quote: 'single' }); 62 | } 63 | 64 | module.exports = transform; 65 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/prop.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createPropExpression, 6 | isFindExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Check if `node` is a `this.$(selector).prop('propName')` expression 13 | * 14 | * @param j 15 | * @param node 16 | * @returns {*|boolean} 17 | */ 18 | function isJQueryExpression(j, node) { 19 | return ( 20 | j.CallExpression.check(node) && 21 | j.MemberExpression.check(node.callee) && 22 | isFindExpression(j, node.callee.object) && 23 | j.Identifier.check(node.callee.property) && 24 | node.callee.property.name === 'prop' && 25 | node.arguments.length === 1 && 26 | j.Literal.check(node.arguments[0]) 27 | ); 28 | } 29 | 30 | /** 31 | * Transforms `this.$(selector).prop('propName')` to `find(selector).propName` 32 | * 33 | * @param file 34 | * @param api 35 | * @returns {*|string} 36 | */ 37 | function transform(file, api) { 38 | let source = file.source; 39 | let j = getParser(api); 40 | 41 | let root = j(source); 42 | 43 | let replacements = root 44 | .find(j.CallExpression) 45 | .filter(({ node }) => isJQueryExpression(j, node)) 46 | .replaceWith(({ node }) => 47 | createPropExpression(j, node.callee.object.arguments, node.arguments[0].value) 48 | ); 49 | if (replacements.length > 0) { 50 | addImportStatement(['find']); 51 | } 52 | 53 | writeImportStatements(j, root); 54 | return root.toSource({ quote: 'single' }); 55 | } 56 | 57 | module.exports = transform; 58 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/route-helpers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { addImportStatement, writeImportStatements } = require('../../utils'); 5 | 6 | /** 7 | * Check if `node` is a currentURL, currentPath, currentRouteName call 8 | * 9 | * @param j 10 | * @param node 11 | * @returns {*|boolean} 12 | */ 13 | function isRouteHelperExpression(j, node, type) { 14 | return ( 15 | j.CallExpression.check(node) && j.Identifier.check(node.callee) && node.callee.name === type 16 | ); 17 | } 18 | 19 | /** 20 | * Add import statements for currentURL, currentPath, currentRouteName 21 | * 22 | * @param file 23 | * @param api 24 | * @returns {*|string} 25 | */ 26 | function transform(file, api) { 27 | let source = file.source; 28 | let j = getParser(api); 29 | 30 | let root = j(source); 31 | 32 | ['currentURL', 'currentPath', 'currentRouteName'].forEach(function (type) { 33 | if ( 34 | root.find(j.CallExpression).filter(({ node }) => isRouteHelperExpression(j, node, type)) 35 | .length > 0 36 | ) { 37 | addImportStatement([type]); 38 | } 39 | }); 40 | 41 | writeImportStatements(j, root); 42 | return root.toSource({ quote: 'single' }); 43 | } 44 | 45 | module.exports = transform; 46 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/tail-eq.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { addImportStatement, migrateSelector, writeImportStatements } = require('../../utils'); 5 | 6 | const sizzleFunctions = ['find', 'click', 'fillIn']; 7 | 8 | /** 9 | * Check if `node` is a selector function call with an :eq pattern as an argument 10 | * 11 | * @param j 12 | * @param node 13 | * @returns {*|boolean} 14 | */ 15 | function isAnEqExpression(j, node) { 16 | return ( 17 | j.CallExpression.check(node) && 18 | j.Identifier.check(node.callee) && 19 | sizzleFunctions.indexOf(node.callee.name) !== -1 && 20 | j.Literal.check(node.arguments[0]) && 21 | typeof node.arguments[0].value === 'string' && 22 | /:eq\(\d+\)$/.test(node.arguments[0].value) 23 | ); 24 | } 25 | 26 | /** 27 | * Transform `find(selector:eq(#))` to `findAll(selector)[#]` 28 | * and `click(selector:eq(#))` to `click(findAll(selector)[#])` 29 | * 30 | * @param file 31 | * @param api 32 | * @returns {*|string} 33 | */ 34 | function transform(file, api) { 35 | let source = file.source; 36 | let j = getParser(api); 37 | 38 | let root = j(source); 39 | 40 | let replacements = root 41 | .find(j.CallExpression) 42 | .filter(({ node }) => isAnEqExpression(j, node)) 43 | .replaceWith(({ node }) => { 44 | let eqExpression = migrateSelector(j, node.arguments[0]); 45 | node.arguments = [eqExpression, ...node.arguments.slice(1)]; 46 | return node; 47 | }); 48 | if (replacements.length > 0) { 49 | addImportStatement(['findAll']); 50 | } 51 | 52 | writeImportStatements(j, root); 53 | return root.toSource({ quote: 'single' }); 54 | } 55 | 56 | module.exports = transform; 57 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/text.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindExpression, 6 | isFindExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Creates a `find(selector).textContent` expression 13 | * 14 | * @param j 15 | * @param findArgs 16 | * @returns {*} 17 | */ 18 | function createExpression(j, findArgs) { 19 | return j.memberExpression(createFindExpression(j, findArgs), j.identifier('textContent')); 20 | } 21 | 22 | /** 23 | * Check if `node` is a `this.$(selector).text()` expression 24 | * 25 | * @param j 26 | * @param node 27 | * @returns {*|boolean} 28 | */ 29 | function isJQueryExpression(j, node) { 30 | return ( 31 | j.CallExpression.check(node) && 32 | j.MemberExpression.check(node.callee) && 33 | isFindExpression(j, node.callee.object) && 34 | j.Identifier.check(node.callee.property) && 35 | node.callee.property.name === 'text' 36 | ); 37 | } 38 | 39 | /** 40 | * Transforms `this.$(selector).text()` to `find(selector).textContent` 41 | * 42 | * @param file 43 | * @param api 44 | * @returns {*|string} 45 | */ 46 | function transform(file, api) { 47 | let source = file.source; 48 | let j = getParser(api); 49 | 50 | let root = j(source); 51 | 52 | let replacements = root 53 | .find(j.CallExpression) 54 | .filter(({ node }) => isJQueryExpression(j, node)) 55 | .replaceWith(({ node }) => createExpression(j, node.callee.object.arguments)); 56 | 57 | if (replacements.length > 0) { 58 | addImportStatement(['find']); 59 | } 60 | 61 | writeImportStatements(j, root); 62 | return root.toSource({ quote: 'single' }); 63 | } 64 | 65 | module.exports = transform; 66 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/trigger-event.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFocusExpression, 6 | createBlurExpression, 7 | makeAwait, 8 | dropAndThen, 9 | addImportStatement, 10 | writeImportStatements, 11 | } = require('../../utils'); 12 | 13 | /** 14 | * Check if `node` is a `triggerEvent(...)` expression 15 | * 16 | * @param j 17 | * @param node 18 | * @returns {*|boolean} 19 | */ 20 | function isGlobalHelperExpression(j, node) { 21 | return ( 22 | j.CallExpression.check(node) && 23 | j.Identifier.check(node.callee) && 24 | node.callee.name === 'triggerEvent' && 25 | node.arguments.length >= 2 && 26 | j.Literal.check(node.arguments[1]) 27 | ); 28 | } 29 | 30 | /** 31 | * Transform `triggerEvent(...)` to `await triggerEvent(...)`, remove `andThen` calls 32 | * Special support for `blur` and `focus` 33 | * 34 | * @param file 35 | * @param api 36 | * @returns {*|string} 37 | */ 38 | function transform(file, api) { 39 | let source = file.source; 40 | let j = getParser(api); 41 | 42 | let root = j(source); 43 | 44 | let replacements = root 45 | .find(j.CallExpression) 46 | .filter(({ node }) => isGlobalHelperExpression(j, node)); 47 | let triggerReplacements = replacements.filter( 48 | ({ node }) => node.arguments[1].value !== 'focus' && node.arguments[1].value !== 'blur' 49 | ); 50 | 51 | let focusReplacements = replacements.filter(({ node }) => node.arguments[1].value === 'focus'); 52 | 53 | let blurReplacements = replacements.filter(({ node }) => node.arguments[1].value === 'blur'); 54 | 55 | if (blurReplacements.length > 0) { 56 | blurReplacements.replaceWith(({ node }) => createBlurExpression(j, node.arguments[0])); 57 | addImportStatement(['blur']); 58 | } 59 | 60 | if (focusReplacements.length > 0) { 61 | focusReplacements.replaceWith(({ node }) => createFocusExpression(j, node.arguments[0])); 62 | addImportStatement(['focus']); 63 | } 64 | 65 | if (triggerReplacements.length > 0) { 66 | makeAwait(j, triggerReplacements); 67 | addImportStatement(['triggerEvent']); 68 | } 69 | 70 | if (replacements.length > 0) { 71 | dropAndThen(j, root); 72 | } 73 | 74 | writeImportStatements(j, root); 75 | return root.toSource({ quote: 'single' }); 76 | } 77 | 78 | module.exports = transform; 79 | -------------------------------------------------------------------------------- /transforms/acceptance/transforms/visit.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | makeAwait, 6 | dropAndThen, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Check if `node` is a `visit(url)` expression 13 | * 14 | * @param j 15 | * @param node 16 | * @returns {*|boolean} 17 | */ 18 | function isGlobalHelperExpression(j, node) { 19 | return ( 20 | j.CallExpression.check(node) && j.Identifier.check(node.callee) && node.callee.name === 'visit' 21 | ); 22 | } 23 | 24 | /** 25 | * Transform `visit(url)` to `await visit(url)`, remove `andThen` calls 26 | * 27 | * @param file 28 | * @param api 29 | * @returns {*|string} 30 | */ 31 | function transform(file, api) { 32 | let source = file.source; 33 | let j = getParser(api); 34 | 35 | let root = j(source); 36 | 37 | let replacements = root 38 | .find(j.CallExpression) 39 | .filter(({ node }) => isGlobalHelperExpression(j, node)); 40 | if (replacements.length > 0) { 41 | makeAwait(j, replacements); 42 | dropAndThen(j, root); 43 | addImportStatement(['visit']); 44 | } 45 | 46 | writeImportStatements(j, root); 47 | return root.toSource({ quote: 'single' }); 48 | } 49 | 50 | module.exports = transform; 51 | -------------------------------------------------------------------------------- /transforms/ember-test-helper-api-migration/README.md: -------------------------------------------------------------------------------- 1 | # ember-test-helper-api-migration 2 | This codemod is to migrate deprecated package `ember-test-helpers` to package `@ember/test-helpers` 3 | 4 | ## Usage 5 | 6 | ``` 7 | npx ember-test-helpers-codemod ember-test-helper-api-migration path/of/files/ or/some**/*glob.js 8 | 9 | # or 10 | 11 | yarn global add ember-test-helpers-codemod 12 | ember-test-helpers-codemod ember-test-helper-api-migration path/of/files/ or/some**/*glob.js 13 | ``` 14 | 15 | ## Input / Output 16 | 17 | 18 | * [basic](#basic) 19 | * [do-not-have-@ember-test-helpers-import](#do-not-have-@ember-test-helpers-import) 20 | * [do-not-have-ember-test-helpers-import](#do-not-have-ember-test-helpers-import) 21 | 22 | 23 | 24 | --- 25 | **basic** 26 | 27 | **Input** ([basic.input.js](transforms/ember-test-helper-api-migration/__testfixtures__/basic.input.js)): 28 | ```js 29 | import { setApplication } from '@ember/test-helpers'; 30 | import { start } from 'ember-qunit'; 31 | import { setResolver } from 'ember-test-helpers'; 32 | ``` 33 | 34 | **Output** ([basic.input.js](transforms/ember-test-helper-api-migration/__testfixtures__/basic.output.js)): 35 | ```js 36 | import { setApplication, setResolver } from '@ember/test-helpers'; 37 | import { start } from 'ember-qunit'; 38 | ``` 39 | --- 40 | **do-not-have-@ember-test-helpers-import** 41 | 42 | **Input** ([do-not-have-@ember-test-helpers-import.input.js](transforms/ember-test-helper-api-migration/__testfixtures__/do-not-have-@ember-test-helpers-import.input.js)): 43 | ```js 44 | import { start } from 'ember-qunit'; 45 | import { setResolver } from 'ember-test-helpers'; 46 | ``` 47 | 48 | **Output** ([do-not-have-@ember-test-helpers-import.input.js](transforms/ember-test-helper-api-migration/__testfixtures__/do-not-have-@ember-test-helpers-import.output.js)): 49 | ```js 50 | import { setResolver } from '@ember/test-helpers'; 51 | import { start } from 'ember-qunit'; 52 | ``` 53 | --- 54 | **do-not-have-ember-test-helpers-import** 55 | 56 | **Input** ([do-not-have-ember-test-helpers-import.input.js](transforms/ember-test-helper-api-migration/__testfixtures__/do-not-have-ember-test-helpers-import.input.js)): 57 | ```js 58 | import { moduleForComponent, test } from 'ember-qunit'; 59 | import hbs from 'htmlbars-inline-precompile'; 60 | 61 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 62 | integration: true 63 | }); 64 | ``` 65 | 66 | **Output** ([do-not-have-ember-test-helpers-import.input.js](transforms/ember-test-helper-api-migration/__testfixtures__/do-not-have-ember-test-helpers-import.output.js)): 67 | ```js 68 | import { moduleForComponent, test } from 'ember-qunit'; 69 | import hbs from 'htmlbars-inline-precompile'; 70 | 71 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 72 | integration: true 73 | }); 74 | ``` 75 | -------------------------------------------------------------------------------- /transforms/ember-test-helper-api-migration/__testfixtures__/basic.input.js: -------------------------------------------------------------------------------- 1 | import { setApplication } from '@ember/test-helpers'; 2 | import { start } from 'ember-qunit'; 3 | import { setResolver } from 'ember-test-helpers'; 4 | 5 | setResolver(engineResolverFor('shared-components')); 6 | 7 | setApplication(Application.create(config.APP)); 8 | preloadAssets(manifest).then(start); 9 | -------------------------------------------------------------------------------- /transforms/ember-test-helper-api-migration/__testfixtures__/basic.output.js: -------------------------------------------------------------------------------- 1 | import { setApplication, setResolver } from '@ember/test-helpers'; 2 | import { start } from 'ember-qunit'; 3 | 4 | setResolver(engineResolverFor('shared-components')); 5 | 6 | setApplication(Application.create(config.APP)); 7 | preloadAssets(manifest).then(start); 8 | -------------------------------------------------------------------------------- /transforms/ember-test-helper-api-migration/__testfixtures__/do-not-have-@ember-test-helpers-import.input.js: -------------------------------------------------------------------------------- 1 | import { start } from 'ember-qunit'; 2 | import { setResolver } from 'ember-test-helpers'; 3 | 4 | setResolver(engineResolverFor('shared-components')); 5 | 6 | setApplication(Application.create(config.APP)); 7 | preloadAssets(manifest).then(start); 8 | -------------------------------------------------------------------------------- /transforms/ember-test-helper-api-migration/__testfixtures__/do-not-have-@ember-test-helpers-import.output.js: -------------------------------------------------------------------------------- 1 | import { setResolver } from '@ember/test-helpers'; 2 | import { start } from 'ember-qunit'; 3 | 4 | setResolver(engineResolverFor('shared-components')); 5 | 6 | setApplication(Application.create(config.APP)); 7 | preloadAssets(manifest).then(start); 8 | -------------------------------------------------------------------------------- /transforms/ember-test-helper-api-migration/__testfixtures__/do-not-have-ember-test-helpers-import.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | -------------------------------------------------------------------------------- /transforms/ember-test-helper-api-migration/__testfixtures__/do-not-have-ember-test-helpers-import.output.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | -------------------------------------------------------------------------------- /transforms/ember-test-helper-api-migration/index.js: -------------------------------------------------------------------------------- 1 | const { getParser } = require('codemod-cli').jscodeshift; 2 | const { addImportStatement, writeImportStatements } = require('../utils'); 3 | 4 | module.exports = function transformer(file, api) { 5 | const j = getParser(api); 6 | const root = j(file.source); 7 | 8 | /** 9 | * Transform imports from ember-test-helpers to @ember/test-helpers 10 | */ 11 | function transform() { 12 | let deprecatedEmberTestHelperStatements = root.find(j.ImportDeclaration, { 13 | source: { value: 'ember-test-helpers' }, 14 | }); 15 | 16 | if (deprecatedEmberTestHelperStatements.length === 0) { 17 | return root.toSource({ 18 | quote: 'single', 19 | trailingComma: true, 20 | }); 21 | } 22 | 23 | let newImports = []; 24 | 25 | deprecatedEmberTestHelperStatements.forEach((importStatement) => { 26 | let oldSpecifiers = importStatement.get('specifiers'); 27 | 28 | oldSpecifiers.each(({ node: specifier }) => { 29 | let importedName = specifier.imported.name; 30 | newImports.push(importedName); 31 | }); 32 | 33 | // Remove "ember-test-helper" import statement 34 | j(importStatement).remove(); 35 | }); 36 | 37 | addImportStatement(newImports); 38 | writeImportStatements(j, root); 39 | } 40 | 41 | transform(); 42 | 43 | return root.toSource({ 44 | quote: 'single', 45 | trailingComma: true, 46 | }); 47 | }; 48 | -------------------------------------------------------------------------------- /transforms/ember-test-helper-api-migration/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { runTransformTest } = require('codemod-cli'); 4 | 5 | runTransformTest({ 6 | type: 'jscodeshift', 7 | name: 'ember-test-helper-api-migration', 8 | }); 9 | -------------------------------------------------------------------------------- /transforms/find/README.md: -------------------------------------------------------------------------------- 1 | # find 2 | 3 | 4 | ## Usage 5 | 6 | ``` 7 | npx ember-test-helpers-codemod find path/of/files/ or/some**/*glob.js 8 | 9 | # or 10 | 11 | yarn global add ember-test-helpers-codemod 12 | ember-test-helpers-codemod find path/of/files/ or/some**/*glob.js 13 | ``` 14 | 15 | ## Input / Output 16 | 17 | 18 | * [find](#find) 19 | 20 | 21 | 22 | --- 23 | **find** 24 | 25 | **Input** ([find.input.js](transforms/find/__testfixtures__/find.input.js)): 26 | ```js 27 | import { find, findAll } from '@ember/test-helpers'; 28 | 29 | test('it renders', function(assert) { 30 | assert.equal(find('.foo').textContent.trim(), 'bar'); 31 | assert.equal(findAll('.bar').length, 2); 32 | }); 33 | ``` 34 | 35 | **Output** ([find.input.js](transforms/find/__testfixtures__/find.output.js)): 36 | ```js 37 | test('it renders', function(assert) { 38 | assert.equal(this.element.querySelector('.foo').textContent.trim(), 'bar'); 39 | assert.equal(this.element.querySelectorAll('.bar').length, 2); 40 | }); 41 | ``` 42 | -------------------------------------------------------------------------------- /transforms/find/__testfixtures__/find.input.js: -------------------------------------------------------------------------------- 1 | import { find, findAll } from '@ember/test-helpers'; 2 | 3 | test('it renders', function(assert) { 4 | assert.equal(find('.foo').textContent.trim(), 'bar'); 5 | assert.equal(findAll('.bar').length, 2); 6 | }); -------------------------------------------------------------------------------- /transforms/find/__testfixtures__/find.output.js: -------------------------------------------------------------------------------- 1 | test('it renders', function(assert) { 2 | assert.equal(this.element.querySelector('.foo').textContent.trim(), 'bar'); 3 | assert.equal(this.element.querySelectorAll('.bar').length, 2); 4 | }); -------------------------------------------------------------------------------- /transforms/find/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { createQuerySelectorExpression, createQuerySelectorAllExpression } = require('../utils'); 5 | 6 | /** 7 | * Transform find/findAll to this.element.querySelector/-All 8 | * 9 | * @param file 10 | * @param api 11 | * @returns {*|string} 12 | */ 13 | function transform(file, api) { 14 | let source = file.source; 15 | let j = getParser(api); 16 | let root = j(source); 17 | 18 | let importStatement = root.find(j.ImportDeclaration, { 19 | source: { value: '@ember/test-helpers' }, 20 | }); 21 | if (importStatement.length === 0) { 22 | return root.toSource({ quote: 'single' }); 23 | } 24 | 25 | let oldSpecifiers = importStatement.get('specifiers'); 26 | let newSpecifiers = []; 27 | oldSpecifiers.each(({ node: specifier }) => { 28 | let importedName = specifier.imported.name; 29 | switch (importedName) { 30 | case 'find': 31 | root 32 | .find(j.CallExpression, { 33 | callee: { 34 | name: 'find', 35 | }, 36 | }) 37 | .replaceWith(({ node }) => createQuerySelectorExpression(j, node.arguments)); 38 | break; 39 | case 'findAll': 40 | root 41 | .find(j.CallExpression, { 42 | callee: { 43 | name: 'findAll', 44 | }, 45 | }) 46 | .replaceWith(({ node }) => createQuerySelectorAllExpression(j, node.arguments)); 47 | break; 48 | default: 49 | newSpecifiers.push(specifier); 50 | } 51 | }); 52 | 53 | if (newSpecifiers.length > 0) { 54 | oldSpecifiers.replace(newSpecifiers); 55 | } else { 56 | importStatement.remove(); 57 | } 58 | 59 | return root.toSource({ quote: 'single' }); 60 | } 61 | 62 | module.exports = transform; 63 | -------------------------------------------------------------------------------- /transforms/find/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { runTransformTest } = require('codemod-cli'); 4 | 5 | runTransformTest({ 6 | type: 'jscodeshift', 7 | name: 'find', 8 | }); 9 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/all.input.js: -------------------------------------------------------------------------------- 1 | import { click } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | function fillInHelper(value) { 10 | this.$('.foo input').val(value); 11 | this.$('.foo input').change(); 12 | } 13 | 14 | test('it renders', async function(assert) { 15 | this.render(hbs`{{foo-bar}}`); 16 | 17 | await click('.foo'); 18 | assert.equal(this.$('.foo').attr('id'), 'foo'); 19 | this.$('.foo input').val('bar').change(); 20 | assert.equal(this.$('.foo').text().trim(), 'foo'); 21 | }); 22 | 23 | test('it renders again', function(assert) { 24 | this.render(hbs`{{foo-bar}}`); 25 | 26 | let selector = '.foo input'; 27 | assert.equal(this.$(selector).length, 1); 28 | assert.equal(this.$(selector).val(), 'foo'); 29 | assert.ok(this.$('.foo').hasClass('selected')); 30 | }); 31 | 32 | test('and again', function(assert) { 33 | this.render(hbs`{{foo-bar}}`); 34 | 35 | this.$('foo').click(); 36 | 37 | fillInHelper.call(this, 'bar'); 38 | assert.ok(this.$('.foo').hasClass('selected')); 39 | }); -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/all.output.js: -------------------------------------------------------------------------------- 1 | import { click, find, findAll, fillIn, blur, triggerEvent } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | async function fillInHelper(value) { 10 | await fillIn('.foo input', value); 11 | await triggerEvent('.foo input', 'change'); 12 | } 13 | 14 | test('it renders', async function(assert) { 15 | this.render(hbs`{{foo-bar}}`); 16 | 17 | await click('.foo'); 18 | assert.equal(find('.foo').id, 'foo'); 19 | await fillIn('.foo input', 'bar'); 20 | await blur('.foo input'); 21 | assert.equal(find('.foo').textContent.trim(), 'foo'); 22 | }); 23 | 24 | test('it renders again', function(assert) { 25 | this.render(hbs`{{foo-bar}}`); 26 | 27 | let selector = '.foo input'; 28 | assert.equal(findAll(selector).length, 1); 29 | assert.equal(find(selector).value, 'foo'); 30 | assert.ok(find('.foo').classList.contains('selected')); 31 | }); 32 | 33 | test('and again', async function(assert) { 34 | this.render(hbs`{{foo-bar}}`); 35 | 36 | await click('foo'); 37 | 38 | fillInHelper.call(this, 'bar'); 39 | assert.ok(find('.foo').classList.contains('selected')); 40 | }); -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/attr.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | this.render(hbs`{{foo-bar}}`); 10 | 11 | assert.equal(this.$('.foo').attr('id'), 'foo'); 12 | assert.equal(this.$('.foo').attr('data-test'), 'foo'); 13 | }); 14 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/attr.output.js: -------------------------------------------------------------------------------- 1 | import { find } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | test('it renders', function(assert) { 10 | this.render(hbs`{{foo-bar}}`); 11 | 12 | assert.equal(find('.foo').id, 'foo'); 13 | assert.equal(find('.foo').getAttribute('data-test'), 'foo'); 14 | }); 15 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/click.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | this.render(hbs`{{foo-bar}}`); 10 | 11 | this.$('.foo').click(); 12 | this.$('.baz a:eq(0)').click(); 13 | this.$('.foo .bar:eq(3)').click(); 14 | assert.ok(true); 15 | }); 16 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/click.output.js: -------------------------------------------------------------------------------- 1 | import { find, findAll, click } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | test('it renders', async function(assert) { 10 | this.render(hbs`{{foo-bar}}`); 11 | 12 | await click('.foo'); 13 | await click(find('.baz a')); 14 | await click(findAll('.foo .bar')[3]); 15 | assert.ok(true); 16 | }); 17 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/default-component-test.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | 10 | // Set any properties with this.set('myProperty', 'value'); 11 | // Handle any actions with this.on('myAction', function(val) { ... }); 12 | 13 | this.render(hbs`{{foo-bar}}`); 14 | 15 | assert.equal(this.$().text().trim(), ''); 16 | 17 | // Template block usage: 18 | this.render(hbs` 19 | {{#foo-bar}} 20 | template block text 21 | {{/foo-barl}} 22 | `); 23 | 24 | assert.equal(this.$().text().trim(), 'template block text'); 25 | }); 26 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/default-component-test.output.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | 10 | // Set any properties with this.set('myProperty', 'value'); 11 | // Handle any actions with this.on('myAction', function(val) { ... }); 12 | 13 | this.render(hbs`{{foo-bar}}`); 14 | 15 | assert.equal(this.element.textContent.trim(), ''); 16 | 17 | // Template block usage: 18 | this.render(hbs` 19 | {{#foo-bar}} 20 | template block text 21 | {{/foo-barl}} 22 | `); 23 | 24 | assert.equal(this.element.textContent.trim(), 'template block text'); 25 | }); 26 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/each.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | test('anonymous function callback with two args', function(assert) { 9 | this.render(hbs`{{foo-bar}}`); 10 | 11 | const elemIds = this.$('.button-class').each((i, val) => { 12 | assert.equal(element.id, `button${index}`); 13 | }); 14 | }); 15 | 16 | test('anonymous function callback with one arg', function(assert) { 17 | this.render(hbs`{{foo-bar}}`); 18 | 19 | const elemIds = this.$('.button-class').each((index) => { 20 | assert.equal(element.id, `button${index}`); 21 | }); 22 | }); 23 | 24 | test('function callback with two args', function(assert) { 25 | this.render(hbs`{{foo-bar}}`); 26 | 27 | const elemIds = this.$('.button-class').each(function(index, element) { 28 | assert.equal(element.id, `button${index}`); 29 | }); 30 | }); 31 | 32 | test('function callback with one arg', function(assert) { 33 | this.render(hbs`{{foo-bar}}`); 34 | 35 | const elemIds = this.$('.button-class').each((index) => { 36 | assert.equal(element.id, `button${index}`); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/each.output.js: -------------------------------------------------------------------------------- 1 | import { findAll } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | test('anonymous function callback with two args', function(assert) { 10 | this.render(hbs`{{foo-bar}}`); 11 | 12 | const elemIds = findAll('.button-class').forEach((val, i) => { 13 | assert.equal(element.id, `button${index}`); 14 | }); 15 | }); 16 | 17 | test('anonymous function callback with one arg', function(assert) { 18 | this.render(hbs`{{foo-bar}}`); 19 | 20 | const elemIds = findAll('.button-class').forEach((element, index) => { 21 | assert.equal(element.id, `button${index}`); 22 | }); 23 | }); 24 | 25 | test('function callback with two args', function(assert) { 26 | this.render(hbs`{{foo-bar}}`); 27 | 28 | const elemIds = findAll('.button-class').forEach(function(element, index) { 29 | assert.equal(element.id, `button${index}`); 30 | }); 31 | }); 32 | 33 | test('function callback with one arg', function(assert) { 34 | this.render(hbs`{{foo-bar}}`); 35 | 36 | const elemIds = findAll('.button-class').forEach((element, index) => { 37 | assert.equal(element.id, `button${index}`); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/event.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | this.render(hbs`{{foo-bar}}`); 10 | 11 | this.$('.foo').change(); 12 | this.$('.foo').submit(); 13 | this.$('.foo').focusin(); 14 | this.$('.foo').focusout(); 15 | this.$('.foo').mousedown(); 16 | this.$('.foo').mouseenter(); 17 | this.$('.foo').mouseleave(); 18 | this.$('.foo').mousemove(); 19 | this.$('.foo').mouseout(); 20 | this.$('.foo').mouseover(); 21 | this.$('.foo').mouseup(); 22 | this.$('.foo').trigger('input'); 23 | this.$('.foo').trigger('click'); 24 | assert.ok(true); 25 | }); 26 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/event.output.js: -------------------------------------------------------------------------------- 1 | import { triggerEvent } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | test('it renders', async function(assert) { 10 | this.render(hbs`{{foo-bar}}`); 11 | 12 | await triggerEvent('.foo', 'change'); 13 | await triggerEvent('.foo', 'submit'); 14 | await triggerEvent('.foo', 'focusin'); 15 | await triggerEvent('.foo', 'focusout'); 16 | await triggerEvent('.foo', 'mousedown'); 17 | await triggerEvent('.foo', 'mouseenter'); 18 | await triggerEvent('.foo', 'mouseleave'); 19 | await triggerEvent('.foo', 'mousemove'); 20 | await triggerEvent('.foo', 'mouseout'); 21 | await triggerEvent('.foo', 'mouseover'); 22 | await triggerEvent('.foo', 'mouseup'); 23 | await triggerEvent('.foo', 'input'); 24 | await click('.foo'); 25 | assert.ok(true); 26 | }); 27 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/focus.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | this.render(hbs`{{foo-bar}}`); 10 | 11 | this.$('.foo').focus(); 12 | assert.ok(true); 13 | }); 14 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/focus.output.js: -------------------------------------------------------------------------------- 1 | import { focus } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | test('it renders', async function(assert) { 10 | this.render(hbs`{{foo-bar}}`); 11 | 12 | await focus('.foo'); 13 | assert.ok(true); 14 | }); 15 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/get-value.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | this.render(hbs`{{foo-bar}}`); 10 | 11 | assert.equal(this.$('.foo').val(), 'foo'); 12 | }); 13 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/get-value.output.js: -------------------------------------------------------------------------------- 1 | import { find } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | test('it renders', function(assert) { 10 | this.render(hbs`{{foo-bar}}`); 11 | 12 | assert.equal(find('.foo').value, 'foo'); 13 | }); 14 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/get.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | test('transforms get() correctly', function(assert) { 9 | assert.ok(this.$('.foo').get(1)); 10 | 11 | const otherGet = someOtherObj.get(1); 12 | }); 13 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/get.output.js: -------------------------------------------------------------------------------- 1 | import { findAll } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | test('transforms get() correctly', function(assert) { 10 | assert.ok(findAll('.foo')[1]); 11 | 12 | const otherGet = someOtherObj.get(1); 13 | }); 14 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/has-class.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | this.render(hbs`{{foo-bar}}`); 10 | 11 | assert.ok(this.$('div').hasClass('foo')); 12 | }); 13 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/has-class.output.js: -------------------------------------------------------------------------------- 1 | import { find } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | test('it renders', function(assert) { 10 | this.render(hbs`{{foo-bar}}`); 11 | 12 | assert.ok(find('div').classList.contains('foo')); 13 | }); 14 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/html.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | this.render(hbs`{{foo-bar}}`); 10 | 11 | assert.equal(this.$('.foo').html().trim(), ''); 12 | 13 | this.$('.bar').html('bar'); 14 | 15 | assert.equal(this.$('.bar').html().trim(), 'bar'); 16 | }); 17 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/html.output.js: -------------------------------------------------------------------------------- 1 | import { find } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | test('it renders', function(assert) { 10 | this.render(hbs`{{foo-bar}}`); 11 | 12 | assert.equal(find('.foo').innerHTML.trim(), ''); 13 | 14 | find('.bar').innerHTML = 'bar'; 15 | 16 | assert.equal(find('.bar').innerHTML.trim(), 'bar'); 17 | }); 18 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/jq-extensions.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | import ANY_SELECTOR_AS_IMPORTED_CONST from './constants'; 4 | 5 | const JQEXTENSION_SELECTOR_AS_LOCAL_CONST = '.foo:first'; 6 | const NORMAL_SELECTOR = '.foo'; 7 | const NORMAL_PSEUDO_SELECTOR = '.foo:eq(0)'; 8 | 9 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 10 | integration: true 11 | }); 12 | 13 | test('it renders', function(assert) { 14 | this.render(hbs`{{foo-bar}}`); 15 | 16 | assert.ok(this.$('.foo:even').length); 17 | assert.ok(this.$('.foo:odd').length); 18 | assert.ok(this.$('.foo:contains(foo)').length); 19 | assert.ok(this.$('.foo:has(p)').length); 20 | assert.ok(this.$('.foo:animated').length); 21 | assert.ok(this.$('.foo:checkbox').length); 22 | assert.ok(this.$('.foo:file').length); 23 | assert.ok(this.$('.foo:first').length); 24 | assert.ok(this.$('.foo:gt(2)').length); 25 | assert.ok(this.$('.foo:header').length); 26 | assert.ok(this.$('.foo:hidden').length); 27 | assert.ok(this.$('.foo:image').length); 28 | assert.ok(this.$('.foo:input').length); 29 | assert.ok(this.$('.foo:last').length); 30 | assert.ok(this.$('.foo:lt(2)').length); 31 | assert.ok(this.$('.foo:parent').length); 32 | assert.ok(this.$('.foo:password').length); 33 | assert.ok(this.$('.foo:radio').length); 34 | assert.ok(this.$('.foo:reset').length); 35 | assert.ok(this.$('.foo:selected').length); 36 | assert.ok(this.$(':selected').length); 37 | assert.ok(this.$('.foo:submit').length); 38 | assert.ok(this.$('.foo:text').length); 39 | assert.ok(this.$('.foo:visible').length); 40 | assert.ok(this.$(JQEXTENSION_SELECTOR_AS_LOCAL_CONST).length); 41 | assert.ok(this.$(ANY_SELECTOR_AS_IMPORTED_CONST).length); 42 | 43 | assert.ok(this.$(':eq(0)').length); 44 | assert.ok(this.$('.foo:eq(0)').length); 45 | assert.ok(this.$('.foo:eq(1)').length); 46 | assert.ok(this.$('.foo:first-child').length); 47 | assert.ok(this.$('.foo:last-child').length); 48 | assert.ok(this.$(NORMAL_SELECTOR).length); 49 | assert.ok(this.$(NORMAL_PSEUDO_SELECTOR).length); 50 | }); 51 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/jq-extensions.output.js: -------------------------------------------------------------------------------- 1 | import { find, findAll } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | import ANY_SELECTOR_AS_IMPORTED_CONST from './constants'; 5 | 6 | const JQEXTENSION_SELECTOR_AS_LOCAL_CONST = '.foo:first'; 7 | const NORMAL_SELECTOR = '.foo'; 8 | const NORMAL_PSEUDO_SELECTOR = '.foo:eq(0)'; 9 | 10 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 11 | integration: true 12 | }); 13 | 14 | test('it renders', function(assert) { 15 | this.render(hbs`{{foo-bar}}`); 16 | 17 | assert.ok(this.$('.foo:even').length); 18 | assert.ok(this.$('.foo:odd').length); 19 | assert.ok(this.$('.foo:contains(foo)').length); 20 | assert.ok(this.$('.foo:has(p)').length); 21 | assert.ok(this.$('.foo:animated').length); 22 | assert.ok(this.$('.foo:checkbox').length); 23 | assert.ok(this.$('.foo:file').length); 24 | assert.ok(this.$('.foo:first').length); 25 | assert.ok(this.$('.foo:gt(2)').length); 26 | assert.ok(this.$('.foo:header').length); 27 | assert.ok(this.$('.foo:hidden').length); 28 | assert.ok(this.$('.foo:image').length); 29 | assert.ok(this.$('.foo:input').length); 30 | assert.ok(this.$('.foo:last').length); 31 | assert.ok(this.$('.foo:lt(2)').length); 32 | assert.ok(this.$('.foo:parent').length); 33 | assert.ok(this.$('.foo:password').length); 34 | assert.ok(this.$('.foo:radio').length); 35 | assert.ok(this.$('.foo:reset').length); 36 | assert.ok(findAll('.foo:checked').length); 37 | assert.ok(this.$(':selected').length); 38 | assert.ok(this.$('.foo:submit').length); 39 | assert.ok(this.$('.foo:text').length); 40 | assert.ok(this.$('.foo:visible').length); 41 | assert.ok(this.$(JQEXTENSION_SELECTOR_AS_LOCAL_CONST).length); 42 | assert.ok(this.$(ANY_SELECTOR_AS_IMPORTED_CONST).length); 43 | 44 | assert.ok(this.$(':eq(0)').length); 45 | assert.ok(findAll(find('.foo')).length); 46 | assert.ok(findAll('.foo')[1].length); 47 | assert.ok(findAll('.foo:first-child').length); 48 | assert.ok(findAll('.foo:last-child').length); 49 | assert.ok(findAll(NORMAL_SELECTOR).length); 50 | assert.ok(this.$(NORMAL_PSEUDO_SELECTOR).length); 51 | }); 52 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/key-event.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | this.render(hbs`{{foo-bar}}`); 10 | 11 | this.$('.foo').trigger('keydown', { keyCode: 13 }); 12 | assert.ok(true); 13 | }); 14 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/key-event.output.js: -------------------------------------------------------------------------------- 1 | import { keyEvent } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | test('it renders', async function(assert) { 10 | this.render(hbs`{{foo-bar}}`); 11 | 12 | await keyEvent('.foo', 'keydown', 13); 13 | assert.ok(true); 14 | }); 15 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/length.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | this.render(hbs`{{foo-bar}}`); 10 | 11 | assert.equal(this.$('.foo').length, 1); 12 | }); 13 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/length.output.js: -------------------------------------------------------------------------------- 1 | import { findAll } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | test('it renders', function(assert) { 10 | this.render(hbs`{{foo-bar}}`); 11 | 12 | assert.equal(findAll('.foo').length, 1); 13 | }); 14 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/prop.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | this.render(hbs`{{foo-bar}}`); 10 | 11 | assert.equal(this.$('.foo').prop('tagName'), 'DIV'); 12 | }); 13 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/prop.output.js: -------------------------------------------------------------------------------- 1 | import { find } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | test('it renders', function(assert) { 10 | this.render(hbs`{{foo-bar}}`); 11 | 12 | assert.equal(find('.foo').tagName, 'DIV'); 13 | }); 14 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/selected.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | 9 | test(':selected is replaced correctly', function(assert) { 10 | // find 11 | const checkedVal = this.$('.foo input:selected').val(); 12 | assert.equal(checkedVal, 13); 13 | 14 | // findAll 15 | const checkedCount = this.$('select option:selected').length; 16 | assert.equal(checkedCount, 3); 17 | 18 | // Multiple jQuery selectors 19 | const firstChecked = this.$('.foo input:selected:eq(0)').val(); 20 | const secondChecked = this.$('.foo input:selected:eq(2)').val(); 21 | }); 22 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/selected.output.js: -------------------------------------------------------------------------------- 1 | import { find, findAll } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | 10 | test(':selected is replaced correctly', function(assert) { 11 | // find 12 | const checkedVal = find('.foo input:checked').value; 13 | assert.equal(checkedVal, 13); 14 | 15 | // findAll 16 | const checkedCount = findAll('select option:checked').length; 17 | assert.equal(checkedCount, 3); 18 | 19 | // Multiple jQuery selectors 20 | const firstChecked = find('.foo input:checked').value; 21 | const secondChecked = find(findAll('.foo input:checked')[2]).value; 22 | }); 23 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/set-value.input.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | test('it renders', function(assert) { 10 | this.render(hbs`{{foo-bar}}`); 11 | 12 | this.$('.foo').val('foo'); 13 | this.$('.foo').val('bar').change(); 14 | this.$('.foo').val('baz').trigger('input'); 15 | Ember.run(() => this.$('select').val('1')); 16 | Ember.run(() => this.$('select').val('1').trigger('change')); 17 | Ember.run(() => this.$('#odd').val(10).trigger('input').trigger('blur')); 18 | this.$('#odd').val(10).trigger('input').trigger('blur'); 19 | this.$('input:eq(0)') 20 | .val('foo') 21 | .trigger('keydown') 22 | .focusout(); 23 | this.$('input:eq(0)') 24 | .val('foo') 25 | .trigger('keydown') 26 | .blur(); 27 | assert.ok(true); 28 | }); 29 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/set-value.output.js: -------------------------------------------------------------------------------- 1 | import { fillIn, blur } from '@ember/test-helpers'; 2 | import Ember from 'ember'; 3 | import { moduleForComponent, test } from 'ember-qunit'; 4 | import hbs from 'htmlbars-inline-precompile'; 5 | 6 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 7 | integration: true 8 | }); 9 | 10 | test('it renders', async function(assert) { 11 | this.render(hbs`{{foo-bar}}`); 12 | 13 | await fillIn('.foo', 'foo'); 14 | await fillIn('.foo', 'bar'); 15 | await blur('.foo'); 16 | await fillIn('.foo', 'baz'); 17 | Ember.run(async () => await fillIn('select', '1')); 18 | Ember.run(() => this.$('select').val('1').trigger('change')); 19 | Ember.run(() => this.$('#odd').val(10).trigger('input').trigger('blur')); 20 | this.$('#odd').val(10).trigger('input').trigger('blur'); 21 | this.$('input:eq(0)') 22 | .val('foo') 23 | .trigger('keydown') 24 | .focusout(); 25 | this.$('input:eq(0)') 26 | .val('foo') 27 | .trigger('keydown') 28 | .blur(); 29 | assert.ok(true); 30 | }); 31 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/text.input.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 5 | integration: true 6 | }); 7 | 8 | test('it renders', function(assert) { 9 | this.render(hbs`{{foo-bar}}`); 10 | 11 | assert.equal(this.$('.foo').text().trim(), ''); 12 | }); 13 | 14 | test('it renders', function(assert) { 15 | this.render(hbs`{{foo-bar}}`); 16 | 17 | assert.equal(this.$().text().trim(), ''); 18 | }); 19 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/text.output.js: -------------------------------------------------------------------------------- 1 | import { find } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | test('it renders', function(assert) { 10 | this.render(hbs`{{foo-bar}}`); 11 | 12 | assert.equal(find('.foo').textContent.trim(), ''); 13 | }); 14 | 15 | test('it renders', function(assert) { 16 | this.render(hbs`{{foo-bar}}`); 17 | 18 | assert.equal(this.element.textContent.trim(), ''); 19 | }); 20 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/typescript.input.ts: -------------------------------------------------------------------------------- 1 | import { click } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | function fillInHelper(value: string) { 10 | this.$('.foo input').val(value); 11 | this.$('.foo input').change(); 12 | } 13 | 14 | test('it renders', async function(assert) { 15 | this.render(hbs`{{foo-bar}}`); 16 | 17 | await click('.foo'); 18 | assert.equal(this.$('.foo').attr('id'), 'foo'); 19 | this.$('.foo input').val('bar').change(); 20 | assert.equal(this.$('.foo').text().trim(), 'foo'); 21 | }); 22 | 23 | test('it renders again', function(assert) { 24 | this.render(hbs`{{foo-bar}}`); 25 | 26 | let selector = '.foo input'; 27 | assert.equal(this.$(selector).length, 1); 28 | assert.equal(this.$(selector).val(), 'foo'); 29 | assert.ok(this.$('.foo').hasClass('selected')); 30 | }); 31 | 32 | test('and again', function(assert) { 33 | this.render(hbs`{{foo-bar}}`); 34 | 35 | this.$('foo').click(); 36 | 37 | fillInHelper.call(this, 'bar'); 38 | assert.ok(this.$('.foo').hasClass('selected')); 39 | }); 40 | -------------------------------------------------------------------------------- /transforms/integration/__testfixtures__/typescript.output.ts: -------------------------------------------------------------------------------- 1 | import { click, find, findAll, fillIn, blur, triggerEvent } from '@ember/test-helpers'; 2 | import { moduleForComponent, test } from 'ember-qunit'; 3 | import hbs from 'htmlbars-inline-precompile'; 4 | 5 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 6 | integration: true 7 | }); 8 | 9 | async function fillInHelper(value: string) { 10 | await fillIn('.foo input', value); 11 | await triggerEvent('.foo input', 'change'); 12 | } 13 | 14 | test('it renders', async function(assert) { 15 | this.render(hbs`{{foo-bar}}`); 16 | 17 | await click('.foo'); 18 | assert.equal(find('.foo').id, 'foo'); 19 | await fillIn('.foo input', 'bar'); 20 | await blur('.foo input'); 21 | assert.equal(find('.foo').textContent.trim(), 'foo'); 22 | }); 23 | 24 | test('it renders again', function(assert) { 25 | this.render(hbs`{{foo-bar}}`); 26 | 27 | let selector = '.foo input'; 28 | assert.equal(findAll(selector).length, 1); 29 | assert.equal(find(selector).value, 'foo'); 30 | assert.ok(find('.foo').classList.contains('selected')); 31 | }); 32 | 33 | test('and again', async function(assert) { 34 | this.render(hbs`{{foo-bar}}`); 35 | 36 | await click('foo'); 37 | 38 | fillInHelper.call(this, 'bar'); 39 | assert.ok(find('.foo').classList.contains('selected')); 40 | }); 41 | -------------------------------------------------------------------------------- /transforms/integration/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const preset = require('../-preset'); 4 | 5 | module.exports = preset('integration'); 6 | -------------------------------------------------------------------------------- /transforms/integration/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { runTransformTest } = require('codemod-cli'); 4 | 5 | runTransformTest({ 6 | type: 'jscodeshift', 7 | name: 'integration', 8 | }); 9 | -------------------------------------------------------------------------------- /transforms/integration/transforms/attr.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindExpression, 6 | createPropExpression, 7 | isJQuerySelectExpression, 8 | addImportStatement, 9 | writeImportStatements, 10 | } = require('../../utils'); 11 | 12 | /** 13 | * Creates a `find(selector).getAttribute(attr)` expression 14 | * 15 | * @param j 16 | * @param findArgs 17 | * @param attr 18 | * @returns {*} 19 | */ 20 | function createAttributeExpression(j, findArgs, attr) { 21 | return j.callExpression( 22 | j.memberExpression(createFindExpression(j, findArgs), j.identifier('getAttribute')), 23 | [attr] 24 | ); 25 | } 26 | 27 | /** 28 | * Check if `node` is a `this.$(selector).attr('foo')` expression 29 | * 30 | * @param j 31 | * @param node 32 | * @returns {*|boolean} 33 | */ 34 | function isJQueryExpression(j, path) { 35 | let node = path.node; 36 | return ( 37 | j.CallExpression.check(node) && 38 | j.MemberExpression.check(node.callee) && 39 | isJQuerySelectExpression(j, node.callee.object, path) && 40 | j.Identifier.check(node.callee.property) && 41 | node.callee.property.name === 'attr' && 42 | node.arguments.length === 1 43 | ); 44 | } 45 | /** 46 | * Should we translate this to a `.getAttribute('foo')` or a `.foo` expression? 47 | * 48 | * @param j 49 | * @param node 50 | * @returns {*|boolean} 51 | */ 52 | function isPropertyAccessPreferred(j, node) { 53 | let arg = node.arguments[0]; 54 | return j.Literal.check(arg) && arg.value === 'id'; 55 | } 56 | 57 | /** 58 | * Transform `this.$(selector).attr('foo')` to `find(selector).getAttribute(attr)` 59 | * 60 | * @param file 61 | * @param api 62 | * @returns {*|string} 63 | */ 64 | function transform(file, api) { 65 | let source = file.source; 66 | let j = getParser(api); 67 | 68 | let root = j(source); 69 | 70 | let propReplacements = root 71 | .find(j.CallExpression) 72 | .filter((path) => isJQueryExpression(j, path)) 73 | .filter(({ node }) => isPropertyAccessPreferred(j, node)) 74 | .replaceWith(({ node }) => 75 | createPropExpression(j, node.callee.object.arguments, node.arguments[0].value) 76 | ); 77 | 78 | let attrReplacements = root 79 | .find(j.CallExpression) 80 | .filter((path) => isJQueryExpression(j, path)) 81 | .filter(({ node }) => !isPropertyAccessPreferred(j, node)) 82 | .replaceWith(({ node }) => 83 | createAttributeExpression(j, node.callee.object.arguments, node.arguments[0]) 84 | ); 85 | 86 | if (propReplacements.length > 0 || attrReplacements.length > 0) { 87 | addImportStatement(['find']); 88 | } 89 | 90 | writeImportStatements(j, root); 91 | return root.toSource({ quote: 'single' }); 92 | } 93 | 94 | module.exports = transform; 95 | -------------------------------------------------------------------------------- /transforms/integration/transforms/click.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createClickExpression, 6 | makeParentFunctionAsync, 7 | isJQuerySelectExpression, 8 | addImportStatement, 9 | writeImportStatements, 10 | } = require('../../utils'); 11 | 12 | /** 13 | * Check if `node` is a `this.$(selector).click()` expression 14 | * 15 | * @param j 16 | * @param node 17 | * @returns {*|boolean} 18 | */ 19 | function isJQueryExpression(j, path) { 20 | let node = path.node; 21 | return ( 22 | j.CallExpression.check(node) && 23 | j.MemberExpression.check(node.callee) && 24 | isJQuerySelectExpression(j, node.callee.object, path) && 25 | j.Identifier.check(node.callee.property) && 26 | node.callee.property.name === 'click' 27 | ); 28 | } 29 | 30 | /** 31 | * Transform `this.$(selector).click()` to `await click(selector)` 32 | * 33 | * @param file 34 | * @param api 35 | * @returns {*|string} 36 | */ 37 | function transform(file, api) { 38 | let source = file.source; 39 | let j = getParser(api); 40 | 41 | let root = j(source); 42 | 43 | let replacements = root 44 | .find(j.CallExpression) 45 | .filter((path) => isJQueryExpression(j, path)) 46 | .replaceWith(({ node }) => createClickExpression(j, node.callee.object.arguments)) 47 | .forEach((path) => makeParentFunctionAsync(j, path)); 48 | if (replacements.length > 0) { 49 | addImportStatement(['click']); 50 | } 51 | 52 | writeImportStatements(j, root); 53 | return root.toSource({ quote: 'single' }); 54 | } 55 | 56 | module.exports = transform; 57 | -------------------------------------------------------------------------------- /transforms/integration/transforms/each.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindAllExpression, 6 | isJQuerySelectExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | transformEachsCallbackArgs, 10 | } = require('../../utils'); 11 | 12 | /** 13 | * Creates a `findAll(selector).forEach()` expression 14 | * 15 | * @param j 16 | * @param findArgs 17 | * @param eachCallback 18 | * @returns {*} 19 | */ 20 | function createExpression(j, findArgs, eachCallback) { 21 | const transformedCallback = transformEachsCallbackArgs(eachCallback); 22 | return j.callExpression( 23 | j.memberExpression(createFindAllExpression(j, findArgs), j.identifier('forEach')), 24 | transformedCallback 25 | ); 26 | } 27 | 28 | /** 29 | * Check if `node` is a `this.$(selector).each()` expression 30 | * 31 | * @param j 32 | * @param node 33 | * @returns {*|boolean} 34 | */ 35 | function isJQueryExpression(j, path) { 36 | let node = path.node; 37 | return ( 38 | j.CallExpression.check(node) && 39 | j.MemberExpression.check(node.callee) && 40 | isJQuerySelectExpression(j, node.callee.object, path) && 41 | j.Identifier.check(node.callee.property) && 42 | node.callee.property.name === 'each' 43 | ); 44 | } 45 | 46 | /** 47 | * Transforms `this.$(selector).each()` to `findAll(selector).forEach()` 48 | * 49 | * @param file 50 | * @param api 51 | * @returns {*|string} 52 | */ 53 | function transform(file, api) { 54 | let source = file.source; 55 | let j = getParser(api); 56 | 57 | let root = j(source); 58 | 59 | let replacements = root 60 | .find(j.CallExpression) 61 | .filter((path) => isJQueryExpression(j, path)) 62 | .replaceWith(({ node }) => createExpression(j, node.callee.object.arguments, node.arguments)); 63 | 64 | if (replacements.length > 0) { 65 | addImportStatement(['findAll']); 66 | } 67 | 68 | writeImportStatements(j, root); 69 | return root.toSource({ quote: 'single' }); 70 | } 71 | 72 | module.exports = transform; 73 | -------------------------------------------------------------------------------- /transforms/integration/transforms/focus.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFocusExpression, 6 | makeParentFunctionAsync, 7 | isJQuerySelectExpression, 8 | addImportStatement, 9 | writeImportStatements, 10 | } = require('../../utils'); 11 | 12 | /** 13 | * Check if `node` is a `this.$(selector).focus()` expression 14 | * 15 | * @param j 16 | * @param node 17 | * @returns {*|boolean} 18 | */ 19 | function isJQueryExpression(j, path) { 20 | let node = path.node; 21 | return ( 22 | j.CallExpression.check(node) && 23 | j.MemberExpression.check(node.callee) && 24 | isJQuerySelectExpression(j, node.callee.object, path) && 25 | j.Identifier.check(node.callee.property) && 26 | node.callee.property.name === 'focus' 27 | ); 28 | } 29 | 30 | /** 31 | * Transform `this.$(selector).focus()` to `await focus(selector)` 32 | * 33 | * @param file 34 | * @param api 35 | * @returns {*|string} 36 | */ 37 | function transform(file, api) { 38 | let source = file.source; 39 | let j = getParser(api); 40 | 41 | let root = j(source); 42 | 43 | let replacements = root 44 | .find(j.CallExpression) 45 | .filter((path) => isJQueryExpression(j, path)) 46 | .replaceWith(({ node }) => createFocusExpression(j, node.callee.object.arguments[0])) 47 | .forEach((path) => makeParentFunctionAsync(j, path)); 48 | if (replacements.length > 0) { 49 | addImportStatement(['focus']); 50 | } 51 | 52 | writeImportStatements(j, root); 53 | return root.toSource({ quote: 'single' }); 54 | } 55 | 56 | module.exports = transform; 57 | -------------------------------------------------------------------------------- /transforms/integration/transforms/get-value.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindExpression, 6 | isJQuerySelectExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Creates a `find(selector).value` expression 13 | * 14 | * @param j 15 | * @param findArgs 16 | * @returns {*} 17 | */ 18 | function createExpression(j, findArgs) { 19 | return j.memberExpression(createFindExpression(j, findArgs), j.identifier('value')); 20 | } 21 | 22 | /** 23 | * Check if `node` is a `this.$(selector).val()` expression 24 | * 25 | * @param j 26 | * @param node 27 | * @returns {*|boolean} 28 | */ 29 | function isJQueryExpression(j, path) { 30 | let node = path.node; 31 | return ( 32 | j.CallExpression.check(node) && 33 | j.MemberExpression.check(node.callee) && 34 | isJQuerySelectExpression(j, node.callee.object, path) && 35 | j.Identifier.check(node.callee.property) && 36 | node.callee.property.name === 'val' && 37 | node.arguments.length === 0 38 | ); 39 | } 40 | 41 | /** 42 | * Transform `this.$(selector).val()` to `find(selector).value` 43 | * 44 | * @param file 45 | * @param api 46 | * @returns {*|string} 47 | */ 48 | function transform(file, api) { 49 | let source = file.source; 50 | let j = getParser(api); 51 | 52 | let root = j(source); 53 | 54 | let replacements = root 55 | .find(j.CallExpression) 56 | .filter((path) => isJQueryExpression(j, path)) 57 | .replaceWith(({ node }) => createExpression(j, node.callee.object.arguments)); 58 | 59 | if (replacements.length > 0) { 60 | addImportStatement(['find']); 61 | } 62 | 63 | writeImportStatements(j, root); 64 | return root.toSource({ quote: 'single' }); 65 | } 66 | 67 | module.exports = transform; 68 | -------------------------------------------------------------------------------- /transforms/integration/transforms/get.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindAllExpression, 6 | isJQuerySelectExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Creates a `findAll(selector)[0]` expression 13 | * 14 | * @param j 15 | * @param findArgs 16 | * @param indexArg 17 | * @returns {*} 18 | */ 19 | function createExpression(j, findArgs, indexArg) { 20 | const index = (indexArg[0] && indexArg[0].value) || 0; 21 | return j.memberExpression(createFindAllExpression(j, findArgs), j.literal(index)); 22 | } 23 | 24 | /** 25 | * Check if `node` is a `this.$(selector).get(0)` expression 26 | * 27 | * @param j 28 | * @param node 29 | * @returns {*|boolean} 30 | */ 31 | function isJQueryExpression(j, path) { 32 | let node = path.node; 33 | return ( 34 | j.CallExpression.check(node) && 35 | j.MemberExpression.check(node.callee) && 36 | isJQuerySelectExpression(j, node.callee.object, path) && 37 | j.Identifier.check(node.callee.property) && 38 | node.callee.property.name === 'get' 39 | ); 40 | } 41 | 42 | /** 43 | * Transforms `this.$(selector).get(0)` to `findAll(selector)[0]` 44 | * 45 | * @param file 46 | * @param api 47 | * @returns {*|string} 48 | */ 49 | function transform(file, api) { 50 | let source = file.source; 51 | let j = getParser(api); 52 | 53 | let root = j(source); 54 | 55 | let replacements = root 56 | .find(j.CallExpression) 57 | .filter((path) => isJQueryExpression(j, path)) 58 | .replaceWith(({ node }) => createExpression(j, node.callee.object.arguments, node.arguments)); 59 | 60 | if (replacements.length > 0) { 61 | addImportStatement(['findAll']); 62 | } 63 | 64 | writeImportStatements(j, root); 65 | return root.toSource({ quote: 'single' }); 66 | } 67 | 68 | module.exports = transform; 69 | -------------------------------------------------------------------------------- /transforms/integration/transforms/has-class.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindExpression, 6 | isJQuerySelectExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Creates a `find(selector).classList.contains(className)` expression 13 | * 14 | * @param j 15 | * @param findArgs 16 | * @param className 17 | * @returns {*} 18 | */ 19 | function createExpression(j, findArgs, className) { 20 | return j.callExpression( 21 | j.memberExpression( 22 | j.memberExpression(createFindExpression(j, findArgs), j.identifier('classList')), 23 | j.identifier('contains') 24 | ), 25 | [className] 26 | ); 27 | } 28 | 29 | /** 30 | * Check if `node` is a `this.$(selector).hasClass(className)` expression 31 | * 32 | * @param j 33 | * @param node 34 | * @returns {*|boolean} 35 | */ 36 | function isJQueryExpression(j, path) { 37 | let node = path.node; 38 | return ( 39 | j.CallExpression.check(node) && 40 | j.MemberExpression.check(node.callee) && 41 | isJQuerySelectExpression(j, node.callee.object, path) && 42 | j.Identifier.check(node.callee.property) && 43 | node.callee.property.name === 'hasClass' 44 | ); 45 | } 46 | 47 | /** 48 | * Transform `this.$(selector).hasClass(className)` to `find(selector)classList.contains(className)` 49 | * 50 | * @param file 51 | * @param api 52 | * @returns {*|string} 53 | */ 54 | function transform(file, api) { 55 | let source = file.source; 56 | let j = getParser(api); 57 | 58 | let root = j(source); 59 | 60 | let replacements = root 61 | .find(j.CallExpression) 62 | .filter((path) => isJQueryExpression(j, path)) 63 | .replaceWith(({ node }) => 64 | createExpression(j, node.callee.object.arguments, node.arguments[0]) 65 | ); 66 | 67 | if (replacements.length > 0) { 68 | addImportStatement(['find']); 69 | } 70 | 71 | writeImportStatements(j, root); 72 | return root.toSource({ quote: 'single' }); 73 | } 74 | 75 | module.exports = transform; 76 | -------------------------------------------------------------------------------- /transforms/integration/transforms/html.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindExpression, 6 | isJQuerySelectExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Creates a `find(selector).innerHTML` expression 13 | * 14 | * @param j 15 | * @param findArgs 16 | * @param attr 17 | * @returns {*} 18 | */ 19 | function createExpression(j, node) { 20 | let findArgs = node.callee.object.arguments; 21 | let findExpression = j.memberExpression( 22 | createFindExpression(j, findArgs), 23 | j.identifier('innerHTML') 24 | ); 25 | 26 | if (node.arguments.length === 0) { 27 | return findExpression; 28 | } else { 29 | return j.assignmentExpression('=', findExpression, node.arguments[0]); 30 | } 31 | } 32 | 33 | /** 34 | * Check if `node` is a `this.$(selector).html()` expression 35 | * 36 | * @param j 37 | * @param node 38 | * @returns {*|boolean} 39 | */ 40 | function isJQueryExpression(j, path) { 41 | let node = path.node; 42 | return ( 43 | j.CallExpression.check(node) && 44 | j.MemberExpression.check(node.callee) && 45 | isJQuerySelectExpression(j, node.callee.object, path) && 46 | j.Identifier.check(node.callee.property) && 47 | node.callee.property.name === 'html' 48 | ); 49 | } 50 | 51 | /** 52 | * Transform `this.$(selector).html()` to `find(selector).innerHTML` 53 | * 54 | * @param file 55 | * @param api 56 | * @returns {*|string} 57 | */ 58 | function transform(file, api) { 59 | let source = file.source; 60 | let j = getParser(api); 61 | 62 | let root = j(source); 63 | 64 | let replacements = root 65 | .find(j.CallExpression) 66 | .filter((path) => isJQueryExpression(j, path)) 67 | .replaceWith(({ node }) => { 68 | return createExpression(j, node); 69 | }); 70 | 71 | if (replacements.length > 0) { 72 | addImportStatement(['find']); 73 | } 74 | 75 | writeImportStatements(j, root); 76 | return root.toSource({ quote: 'single' }); 77 | } 78 | 79 | module.exports = transform; 80 | -------------------------------------------------------------------------------- /transforms/integration/transforms/key-event.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | migrateSelector, 6 | makeParentFunctionAsync, 7 | isJQuerySelectExpression, 8 | addImportStatement, 9 | writeImportStatements, 10 | } = require('../../utils'); 11 | 12 | /** 13 | * Creates a `await keyEvent(selector, eventName, keyCode)` expression 14 | * 15 | * @param j 16 | * @param selector 17 | * @param eventName 18 | * @param keyCode 19 | * @returns {*} 20 | */ 21 | function createExpression(j, selector, eventName, keyCode) { 22 | return j.awaitExpression( 23 | j.callExpression(j.identifier('keyEvent'), [migrateSelector(j, selector), eventName, keyCode]) 24 | ); 25 | } 26 | 27 | /** 28 | * Check if `node` is a `this.$(selector).trigger(eventName, { keyCode: num })` expression 29 | * 30 | * @param j 31 | * @param node 32 | * @returns {*|boolean} 33 | */ 34 | function isJQueryExpression(j, path) { 35 | let node = path.node; 36 | return ( 37 | j.CallExpression.check(node) && 38 | j.MemberExpression.check(node.callee) && 39 | isJQuerySelectExpression(j, node.callee.object, path) && 40 | j.Identifier.check(node.callee.property) && 41 | node.callee.property.name === 'trigger' && 42 | node.arguments.length === 2 && 43 | j.ObjectExpression.check(node.arguments[1]) && 44 | node.arguments[1] && 45 | j.Identifier.check(node.arguments[1].properties[0].key) && 46 | node.arguments[1].properties[0].key.name === 'keyCode' 47 | ); 48 | } 49 | 50 | /** 51 | * Transforms `this.$(selector).trigger(eventName, { keyCode: num })` to `await keyEvent(selector, eventName, keyCode)` 52 | * 53 | * @param file 54 | * @param api 55 | * @returns {*|string} 56 | */ 57 | function transform(file, api) { 58 | let source = file.source; 59 | let j = getParser(api); 60 | 61 | let root = j(source); 62 | 63 | let replacements = root 64 | .find(j.CallExpression) 65 | .filter((path) => isJQueryExpression(j, path)) 66 | .replaceWith(({ node }) => 67 | createExpression( 68 | j, 69 | node.callee.object.arguments[0], 70 | node.arguments[0], 71 | node.arguments[1].properties[0].value 72 | ) 73 | ) 74 | .forEach((path) => makeParentFunctionAsync(j, path)); 75 | if (replacements.length > 0) { 76 | addImportStatement(['keyEvent']); 77 | } 78 | 79 | writeImportStatements(j, root); 80 | return root.toSource({ quote: 'single' }); 81 | } 82 | 83 | module.exports = transform; 84 | -------------------------------------------------------------------------------- /transforms/integration/transforms/length.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindAllExpression, 6 | isJQuerySelectExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Creates a `findAll(selector).length` expression 13 | * 14 | * @param j 15 | * @param findArgs 16 | * @returns {*} 17 | */ 18 | function createExpression(j, findArgs) { 19 | return j.memberExpression(createFindAllExpression(j, findArgs), j.identifier('length')); 20 | } 21 | 22 | /** 23 | * Check if `node` is a `this.$(selector).length` expression 24 | * 25 | * @param j 26 | * @param node 27 | * @returns {*|boolean} 28 | */ 29 | function isJQueryExpression(j, path) { 30 | let node = path.node; 31 | return ( 32 | j.MemberExpression.check(node) && 33 | isJQuerySelectExpression(j, node.object, path) && 34 | j.Identifier.check(node.property) && 35 | node.property.name === 'length' 36 | ); 37 | } 38 | 39 | /** 40 | * Transforms `this.$(selector).length` to `findAll(selector).length` 41 | * 42 | * @param file 43 | * @param api 44 | * @returns {*|string} 45 | */ 46 | function transform(file, api) { 47 | let source = file.source; 48 | let j = getParser(api); 49 | 50 | let root = j(source); 51 | 52 | let replacements = root 53 | .find(j.MemberExpression) 54 | .filter((path) => isJQueryExpression(j, path)) 55 | .replaceWith(({ node }) => createExpression(j, node.object.arguments)); 56 | 57 | if (replacements.length > 0) { 58 | addImportStatement(['findAll']); 59 | } 60 | 61 | writeImportStatements(j, root); 62 | return root.toSource({ quote: 'single' }); 63 | } 64 | 65 | module.exports = transform; 66 | -------------------------------------------------------------------------------- /transforms/integration/transforms/prop.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createPropExpression, 6 | isJQuerySelectExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Check if `node` is a `this.$(selector).prop('propName')` expression 13 | * 14 | * @param j 15 | * @param node 16 | * @returns {*|boolean} 17 | */ 18 | function isJQueryExpression(j, path) { 19 | let node = path.node; 20 | return ( 21 | j.CallExpression.check(node) && 22 | j.MemberExpression.check(node.callee) && 23 | isJQuerySelectExpression(j, node.callee.object, path) && 24 | j.Identifier.check(node.callee.property) && 25 | node.callee.property.name === 'prop' && 26 | node.arguments.length === 1 && 27 | j.Literal.check(node.arguments[0]) 28 | ); 29 | } 30 | 31 | /** 32 | * Transforms `this.$(selector).prop('propName')` to `find(selector).propName` 33 | * 34 | * @param file 35 | * @param api 36 | * @returns {*|string} 37 | */ 38 | function transform(file, api) { 39 | let source = file.source; 40 | let j = getParser(api); 41 | 42 | let root = j(source); 43 | 44 | let replacements = root 45 | .find(j.CallExpression) 46 | .filter((path) => isJQueryExpression(j, path)) 47 | .replaceWith(({ node }) => 48 | createPropExpression(j, node.callee.object.arguments, node.arguments[0].value) 49 | ); 50 | if (replacements.length > 0) { 51 | addImportStatement(['find']); 52 | } 53 | 54 | writeImportStatements(j, root); 55 | return root.toSource({ quote: 'single' }); 56 | } 57 | 58 | module.exports = transform; 59 | -------------------------------------------------------------------------------- /transforms/integration/transforms/set-value.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | migrateSelector, 6 | makeParentFunctionAsync, 7 | isJQuerySelectExpression, 8 | addImportStatement, 9 | writeImportStatements, 10 | } = require('../../utils'); 11 | 12 | /** 13 | * Creates a `await fillIn(selector, value)` expression 14 | * 15 | * @param j 16 | * @param selector 17 | * @param value 18 | * @returns {*} 19 | */ 20 | function createExpression(j, selector, value) { 21 | return j.awaitExpression( 22 | j.callExpression(j.identifier('fillIn'), [migrateSelector(j, selector), value]) 23 | ); 24 | } 25 | 26 | /** 27 | * Creates a `await blur(selector)` expression 28 | * 29 | * @param j 30 | * @param selector 31 | * @returns {*} 32 | */ 33 | function createBlurExpression(j, selector) { 34 | return j.awaitExpression(j.callExpression(j.identifier('blur'), [migrateSelector(j, selector)])); 35 | } 36 | 37 | /** 38 | * Check if `node` is a `this.$(selector).val(someValue)` expression not in an arrow function 39 | * 40 | * @param j 41 | * @param node 42 | * @returns {*|boolean} 43 | */ 44 | function isJQueryExpression(j, path) { 45 | let node = path.node; 46 | return ( 47 | j.CallExpression.check(node) && 48 | j.MemberExpression.check(node.callee) && 49 | isJQuerySelectExpression(j, node.callee.object, path) && 50 | j.Identifier.check(node.callee.property) && 51 | node.callee.property.name === 'val' && 52 | node.arguments.length > 0 && 53 | // if it has a fluent trigger call, it may not be inside an arrow function 54 | (!hasFluentTriggerCall(j, path) || 55 | (!j.ArrowFunctionExpression.check(path.parent.parent.parent.node) && 56 | !hasFluentTriggerCall(j, path.parent.parent))) && 57 | !hasFluentTriggerAndMoreCall(j, path) 58 | ); 59 | } 60 | 61 | function hasFluentTriggerCall(j, path) { 62 | let parent = path.parent && path.parent.node; 63 | let grandParent = parent && path.parent.parent.node; 64 | return ( 65 | parent && 66 | grandParent && 67 | j.MemberExpression.check(parent) && 68 | j.Identifier.check(parent.property) && 69 | parent.property.name === 'trigger' && 70 | j.CallExpression.check(grandParent) 71 | ); 72 | } 73 | 74 | function hasFluentTriggerAndMoreCall(j, path) { 75 | const greatGrandParent = path.parentPath.parentPath.parentPath.node; 76 | return greatGrandParent && j.MemberExpression.check(greatGrandParent); 77 | } 78 | 79 | function hasFluentChangeCall(j, path) { 80 | let parent = path.parent && path.parent.node; 81 | let grandParent = parent && path.parent.parent.node; 82 | return ( 83 | parent && 84 | grandParent && 85 | j.MemberExpression.check(parent) && 86 | j.Identifier.check(parent.property) && 87 | parent.property.name === 'change' && 88 | j.CallExpression.check(grandParent) 89 | ); 90 | } 91 | 92 | /** 93 | * Transforms `this.$(selector).val(value)` to `await fillIn(selector, value)` 94 | * 95 | * See test for more transformation examples 96 | * 97 | * @param file 98 | * @param api 99 | * @returns {*|string} 100 | */ 101 | function transform(file, api) { 102 | let source = file.source; 103 | let j = getParser(api); 104 | 105 | let root = j(source); 106 | 107 | let replacements = root 108 | .find(j.CallExpression) 109 | .filter((path) => isJQueryExpression(j, path)) 110 | .replaceWith(({ node }) => 111 | createExpression(j, node.callee.object.arguments[0], node.arguments[0]) 112 | ) 113 | .forEach((path) => makeParentFunctionAsync(j, path)); 114 | 115 | replacements 116 | .filter((path) => hasFluentTriggerCall(j, path)) 117 | .map((path) => path.parent.parent.parent) 118 | .replaceWith((path) => j.expressionStatement(path.node.expression.callee.object)) 119 | .forEach((path) => makeParentFunctionAsync(j, path)); 120 | 121 | let changeReplacements = replacements 122 | .filter((path) => hasFluentChangeCall(j, path)) 123 | .map((path) => path.parent.parent.parent) 124 | .insertAfter((path) => 125 | j.expressionStatement( 126 | createBlurExpression(j, path.node.expression.callee.object.argument.arguments[0]) 127 | ) 128 | ) 129 | .replaceWith((path) => j.expressionStatement(path.node.expression.callee.object)) 130 | .forEach((path) => makeParentFunctionAsync(j, path)); 131 | 132 | if (replacements.length > 0) { 133 | addImportStatement(['fillIn']); 134 | } 135 | 136 | if (changeReplacements.length > 0) { 137 | addImportStatement(['blur']); 138 | } 139 | 140 | writeImportStatements(j, root); 141 | return root.toSource({ quote: 'single' }); 142 | } 143 | 144 | module.exports = transform; 145 | -------------------------------------------------------------------------------- /transforms/integration/transforms/text.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | createFindExpression, 6 | isJQuerySelectExpression, 7 | addImportStatement, 8 | writeImportStatements, 9 | } = require('../../utils'); 10 | 11 | /** 12 | * Creates a `find(selector).textContent` expression 13 | * 14 | * @param j 15 | * @param findArgs 16 | * @returns {*} 17 | */ 18 | function createExpression(j, findArgs) { 19 | if (findArgs.length === 0) { 20 | return j.memberExpression( 21 | j.memberExpression(j.thisExpression(), j.identifier('element')), 22 | j.identifier('textContent') 23 | ); 24 | } 25 | return j.memberExpression(createFindExpression(j, findArgs), j.identifier('textContent')); 26 | } 27 | 28 | /** 29 | * Check if `node` is a `this.$(selector).text()` expression 30 | * 31 | * @param j 32 | * @param node 33 | * @returns {*|boolean} 34 | */ 35 | function isJQueryExpression(j, path) { 36 | let node = path.node; 37 | return ( 38 | j.CallExpression.check(node) && 39 | j.MemberExpression.check(node.callee) && 40 | isJQuerySelectExpression(j, node.callee.object, path) && 41 | j.Identifier.check(node.callee.property) && 42 | node.callee.property.name === 'text' 43 | ); 44 | } 45 | 46 | /** 47 | * Transforms `this.$(selector).text()` to `find(selector).textContent` 48 | * 49 | * @param file 50 | * @param api 51 | * @returns {*|string} 52 | */ 53 | function transform(file, api) { 54 | let source = file.source; 55 | let j = getParser(api); 56 | 57 | let root = j(source); 58 | 59 | let replacements = root 60 | .find(j.CallExpression) 61 | .filter((path) => isJQueryExpression(j, path)) 62 | .replaceWith(({ node }) => createExpression(j, node.callee.object.arguments)); 63 | 64 | if (replacements.length > 0) { 65 | addImportStatement(['find']); 66 | } 67 | 68 | writeImportStatements(j, root); 69 | return root.toSource({ quote: 'single' }); 70 | } 71 | 72 | module.exports = transform; 73 | -------------------------------------------------------------------------------- /transforms/integration/transforms/trigger-shortcut.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | makeParentFunctionAsync, 6 | createTriggerExpression, 7 | isJQuerySelectExpression, 8 | addImportStatement, 9 | writeImportStatements, 10 | } = require('../../utils'); 11 | 12 | const triggerShortcuts = [ 13 | 'change', 14 | 'submit', 15 | 'focusout', 16 | 'focusin', 17 | 'mousedown', 18 | 'mouseenter', 19 | 'mouseleave', 20 | 'mousemove', 21 | 'mouseout', 22 | 'mouseover', 23 | 'mouseup', 24 | ]; 25 | 26 | /** 27 | * Check if `node` is a `this.$(selector).change()`or some other trigger shortcut expression 28 | * 29 | * @param j 30 | * @param node 31 | * @returns {*|boolean} 32 | */ 33 | function isJQueryExpression(j, path) { 34 | let node = path.node; 35 | return ( 36 | j.CallExpression.check(node) && 37 | j.MemberExpression.check(node.callee) && 38 | isJQuerySelectExpression(j, node.callee.object, path) && 39 | j.Identifier.check(node.callee.property) && 40 | triggerShortcuts.indexOf(node.callee.property.name) !== -1 41 | ); 42 | } 43 | 44 | /** 45 | * Transforms `this.$(selector).()` to `await triggerEvent(selector, eventName)` 46 | * 47 | * @param file 48 | * @param api 49 | * @returns {*|string} 50 | */ 51 | function transform(file, api) { 52 | let source = file.source; 53 | let j = getParser(api); 54 | 55 | let root = j(source); 56 | 57 | let replacements = root 58 | .find(j.CallExpression) 59 | .filter((path) => isJQueryExpression(j, path)) 60 | .replaceWith(({ node }) => 61 | createTriggerExpression( 62 | j, 63 | node.callee.object.arguments[0], 64 | j.literal(node.callee.property.name) 65 | ) 66 | ) 67 | .forEach((path) => makeParentFunctionAsync(j, path)); 68 | if (replacements.length > 0) { 69 | addImportStatement(['triggerEvent']); 70 | } 71 | 72 | writeImportStatements(j, root); 73 | return root.toSource({ quote: 'single' }); 74 | } 75 | 76 | module.exports = transform; 77 | -------------------------------------------------------------------------------- /transforms/integration/transforms/trigger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { 5 | makeParentFunctionAsync, 6 | createTriggerExpression, 7 | createClickExpression, 8 | isJQuerySelectExpression, 9 | addImportStatement, 10 | writeImportStatements, 11 | } = require('../../utils'); 12 | 13 | /** 14 | * Check if `node` is a `this.$(selector).trigger(eventName)` expression 15 | * 16 | * @param j 17 | * @param node 18 | * @returns {*|boolean} 19 | */ 20 | function isJQueryExpression(j, path) { 21 | let node = path.node; 22 | return ( 23 | j.CallExpression.check(node) && 24 | j.MemberExpression.check(node.callee) && 25 | isJQuerySelectExpression(j, node.callee.object, path) && 26 | j.Identifier.check(node.callee.property) && 27 | node.callee.property.name === 'trigger' && 28 | node.arguments.length === 1 && 29 | j.Literal.check(node.arguments[0]) 30 | ); 31 | } 32 | 33 | /** 34 | * Transforms `this.$(selector).trigger(eventName)` to `await triggerEvent(selector, eventName)` 35 | * Special case: `this.$(selector).trigger('click')` is transformed to `await click(selector)` 36 | * 37 | * @param file 38 | * @param api 39 | * @returns {*|string} 40 | */ 41 | function transform(file, api) { 42 | let source = file.source; 43 | let j = getParser(api); 44 | 45 | let root = j(source); 46 | let replacements = root 47 | .find(j.CallExpression) 48 | .filter((path) => isJQueryExpression(j, path)) 49 | .replaceWith(({ node }) => { 50 | let selector = node.callee.object.arguments[0]; 51 | let eventName = node.arguments[0]; 52 | if (eventName && eventName.value === 'click') { 53 | return createClickExpression(j, node.callee.object.arguments); 54 | } else { 55 | return createTriggerExpression(j, selector, eventName); 56 | } 57 | }) 58 | .forEach((path) => makeParentFunctionAsync(j, path)); 59 | if (replacements.length > 0) { 60 | addImportStatement(['triggerEvent']); 61 | } 62 | 63 | writeImportStatements(j, root); 64 | return root.toSource({ quote: 'single' }); 65 | } 66 | 67 | module.exports = transform; 68 | -------------------------------------------------------------------------------- /transforms/native-dom/README.md: -------------------------------------------------------------------------------- 1 | # native-dom 2 | 3 | 4 | ## Usage 5 | 6 | ``` 7 | npx ember-test-helpers-codemod native-dom path/of/files/ or/some**/*glob.js 8 | 9 | # or 10 | 11 | yarn global add ember-test-helpers-codemod 12 | ember-test-helpers-codemod native-dom path/of/files/ or/some**/*glob.js 13 | ``` 14 | 15 | ## Input / Output 16 | 17 | 18 | * [acceptance](#acceptance) 19 | * [double-import](#double-import) 20 | * [integration](#integration) 21 | * [prune-import](#prune-import) 22 | 23 | 24 | 25 | --- 26 | **acceptance** 27 | 28 | **Input** ([acceptance.input.js](transforms/native-dom/__testfixtures__/acceptance.input.js)): 29 | ```js 30 | import { find, visit } from 'ember-native-dom-helpers'; 31 | import { currentURL, currentPath, currentRouteName } from 'ember-native-dom-helpers'; 32 | import { test } from 'qunit'; 33 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 34 | 35 | moduleForAcceptance('click'); 36 | 37 | test('visiting /foo', async function(assert) { 38 | await visit('/foo'); 39 | assert.equal(currentURL(), '/foo'); 40 | assert.ok(find('.foo')); 41 | }); 42 | 43 | test('visiting /bar', async function(assert) { 44 | await visit('/bar'); 45 | assert.equal(currentPath(), 'bar'); 46 | }); 47 | 48 | test('visiting /bar', async function(assert) { 49 | await visit('/bar'); 50 | assert.equal(currentRouteName(), 'bar.index'); 51 | }); 52 | 53 | ``` 54 | 55 | **Output** ([acceptance.input.js](transforms/native-dom/__testfixtures__/acceptance.output.js)): 56 | ```js 57 | import { find, visit, currentURL, currentRouteName } from '@ember/test-helpers'; 58 | import { currentPath } from 'ember-native-dom-helpers'; 59 | import { test } from 'qunit'; 60 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 61 | 62 | moduleForAcceptance('click'); 63 | 64 | test('visiting /foo', async function(assert) { 65 | await visit('/foo'); 66 | assert.equal(currentURL(), '/foo'); 67 | assert.ok(find('.foo')); 68 | }); 69 | 70 | test('visiting /bar', async function(assert) { 71 | await visit('/bar'); 72 | assert.equal(currentPath(), 'bar'); 73 | }); 74 | 75 | test('visiting /bar', async function(assert) { 76 | await visit('/bar'); 77 | assert.equal(currentRouteName(), 'bar.index'); 78 | }); 79 | 80 | ``` 81 | --- 82 | **double-import** 83 | 84 | **Input** ([double-import.input.js](transforms/native-dom/__testfixtures__/double-import.input.js)): 85 | ```js 86 | import { click, currentURL } from 'ember-native-dom-helpers'; 87 | import { find, visit } from 'ember-native-dom-helpers'; 88 | 89 | ``` 90 | 91 | **Output** ([double-import.input.js](transforms/native-dom/__testfixtures__/double-import.output.js)): 92 | ```js 93 | import { click, currentURL, find, visit } from '@ember/test-helpers'; 94 | 95 | ``` 96 | --- 97 | **integration** 98 | 99 | **Input** ([integration.input.js](transforms/native-dom/__testfixtures__/integration.input.js)): 100 | ```js 101 | import { 102 | click, 103 | find, 104 | findAll, 105 | findWithAssert, 106 | fillIn, 107 | focus, 108 | blur, 109 | triggerEvent, 110 | keyEvent, 111 | scrollTo, 112 | selectFiles, 113 | waitFor, 114 | waitUntil, 115 | } from 'ember-native-dom-helpers'; 116 | import { moduleForComponent, test } from 'ember-qunit'; 117 | import hbs from 'htmlbars-inline-precompile'; 118 | 119 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 120 | integration: true 121 | }); 122 | 123 | test('it renders', async function(assert) { 124 | this.render(hbs`{{foo-bar}}`); 125 | 126 | await click('.foo', {}); 127 | assert.equal(find('.foo').id, 'foo'); 128 | await fillIn('.foo input', 'bar'); 129 | await blur('.foo input'); 130 | assert.equal(find('.foo').textContent.trim(), 'foo'); 131 | }); 132 | 133 | test('it renders again', function(assert) { 134 | this.render(hbs`{{foo-bar}}`); 135 | 136 | let selector = '.foo input'; 137 | assert.equal(findAll(selector).length, 1); 138 | assert.equal(find(selector).value, 'foo'); 139 | assert.ok(find('.foo').classList.contains('selected')); 140 | }); 141 | 142 | test('and again', async function(assert) { 143 | this.render(hbs`{{foo-bar}}`); 144 | 145 | await tap('foo'); 146 | let el = findWithAssert('.foo input'); 147 | 148 | await fillIn(el, value); 149 | await triggerEvent('.foo input', 'change'); 150 | await keyEvent('bar', 'keypress', 13, modifiers); 151 | 152 | await focus('.foo input'); 153 | await blur('.foo input'); 154 | 155 | assert.ok(findAll('.baz')[1].classList.contains('selected')); 156 | }); 157 | 158 | test('and yet again', async function(assert) { 159 | this.render(hbs`{{foo-bar}}`); 160 | 161 | await scrollTo(document, 10, 20); 162 | await selectFiles('input[type=file]', [new Blob(['texters'], { type: 'plain/text' })]); 163 | await waitUntil(() => find('.foo.active')); 164 | await waitFor('.bar.selected'); 165 | assert.ok(true); 166 | }); 167 | 168 | ``` 169 | 170 | **Output** ([integration.input.js](transforms/native-dom/__testfixtures__/integration.output.js)): 171 | ```js 172 | import { 173 | click, 174 | find, 175 | findAll, 176 | fillIn, 177 | focus, 178 | blur, 179 | triggerEvent, 180 | triggerKeyEvent, 181 | waitFor, 182 | waitUntil, 183 | } from '@ember/test-helpers'; 184 | 185 | import { findWithAssert, scrollTo, selectFiles } from 'ember-native-dom-helpers'; 186 | import { moduleForComponent, test } from 'ember-qunit'; 187 | import hbs from 'htmlbars-inline-precompile'; 188 | 189 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 190 | integration: true 191 | }); 192 | 193 | test('it renders', async function(assert) { 194 | this.render(hbs`{{foo-bar}}`); 195 | 196 | await click('.foo', {}); 197 | assert.equal(find('.foo').id, 'foo'); 198 | await fillIn('.foo input', 'bar'); 199 | await blur('.foo input'); 200 | assert.equal(find('.foo').textContent.trim(), 'foo'); 201 | }); 202 | 203 | test('it renders again', function(assert) { 204 | this.render(hbs`{{foo-bar}}`); 205 | 206 | let selector = '.foo input'; 207 | assert.equal(findAll(selector).length, 1); 208 | assert.equal(find(selector).value, 'foo'); 209 | assert.ok(find('.foo').classList.contains('selected')); 210 | }); 211 | 212 | test('and again', async function(assert) { 213 | this.render(hbs`{{foo-bar}}`); 214 | 215 | await tap('foo'); 216 | let el = findWithAssert('.foo input'); 217 | 218 | await fillIn(el, value); 219 | await triggerEvent('.foo input', 'change'); 220 | await triggerKeyEvent('bar', 'keypress', 13, modifiers); 221 | 222 | await focus('.foo input'); 223 | await blur('.foo input'); 224 | 225 | assert.ok(findAll('.baz')[1].classList.contains('selected')); 226 | }); 227 | 228 | test('and yet again', async function(assert) { 229 | this.render(hbs`{{foo-bar}}`); 230 | 231 | await scrollTo(document, 10, 20); 232 | await selectFiles('input[type=file]', [new Blob(['texters'], { type: 'plain/text' })]); 233 | await waitUntil(() => find('.foo.active')); 234 | await waitFor('.bar.selected'); 235 | assert.ok(true); 236 | }); 237 | 238 | ``` 239 | --- 240 | **prune-import** 241 | 242 | **Input** ([prune-import.input.js](transforms/native-dom/__testfixtures__/prune-import.input.js)): 243 | ```js 244 | import { click } from 'ember-native-dom-helpers'; 245 | 246 | ``` 247 | 248 | **Output** ([prune-import.input.js](transforms/native-dom/__testfixtures__/prune-import.output.js)): 249 | ```js 250 | import { click } from '@ember/test-helpers'; 251 | 252 | ``` 253 | -------------------------------------------------------------------------------- /transforms/native-dom/__testfixtures__/acceptance.input.js: -------------------------------------------------------------------------------- 1 | import { find, visit } from 'ember-native-dom-helpers'; 2 | import { currentURL, currentPath, currentRouteName } from 'ember-native-dom-helpers'; 3 | import { test } from 'qunit'; 4 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 5 | 6 | moduleForAcceptance('click'); 7 | 8 | test('visiting /foo', async function(assert) { 9 | await visit('/foo'); 10 | assert.equal(currentURL(), '/foo'); 11 | assert.ok(find('.foo')); 12 | }); 13 | 14 | test('visiting /bar', async function(assert) { 15 | await visit('/bar'); 16 | assert.equal(currentPath(), 'bar'); 17 | }); 18 | 19 | test('visiting /bar', async function(assert) { 20 | await visit('/bar'); 21 | assert.equal(currentRouteName(), 'bar.index'); 22 | }); 23 | -------------------------------------------------------------------------------- /transforms/native-dom/__testfixtures__/acceptance.output.js: -------------------------------------------------------------------------------- 1 | import { find, visit, currentURL, currentRouteName } from '@ember/test-helpers'; 2 | import { currentPath } from 'ember-native-dom-helpers'; 3 | import { test } from 'qunit'; 4 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 5 | 6 | moduleForAcceptance('click'); 7 | 8 | test('visiting /foo', async function(assert) { 9 | await visit('/foo'); 10 | assert.equal(currentURL(), '/foo'); 11 | assert.ok(find('.foo')); 12 | }); 13 | 14 | test('visiting /bar', async function(assert) { 15 | await visit('/bar'); 16 | assert.equal(currentPath(), 'bar'); 17 | }); 18 | 19 | test('visiting /bar', async function(assert) { 20 | await visit('/bar'); 21 | assert.equal(currentRouteName(), 'bar.index'); 22 | }); 23 | -------------------------------------------------------------------------------- /transforms/native-dom/__testfixtures__/context-argument.input.js: -------------------------------------------------------------------------------- 1 | import { find, findAll, visit, click, fillIn } from 'ember-native-dom-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('click'); 6 | 7 | test('visiting /foo', async function(assert) { 8 | await visit('/foo'); 9 | 10 | const foo = find('.foo'); 11 | assert.equal(find('.bar', foo).textContent.trim(), 'bar'); 12 | assert.equal(find('.bar', find('.foo')).textContent.trim(), 'bar'); 13 | assert.equal(find('.bar', '.foo').textContent.trim(), 'bar'); 14 | assert.equal(findAll('.bar', foo).length, 2); 15 | assert.equal(findAll('.bar', find('.foo')).length, 2); 16 | assert.equal(findAll('.bar', '.foo').length, 2); 17 | 18 | await click('button', foo); 19 | await click('button', { shiftKey: true }); 20 | await click('button', foo, { shiftKey: true }); 21 | }); 22 | -------------------------------------------------------------------------------- /transforms/native-dom/__testfixtures__/context-argument.output.js: -------------------------------------------------------------------------------- 1 | import { find, findAll, visit, click } from '@ember/test-helpers'; 2 | import { test } from 'qunit'; 3 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 4 | 5 | moduleForAcceptance('click'); 6 | 7 | test('visiting /foo', async function(assert) { 8 | await visit('/foo'); 9 | 10 | const foo = find('.foo'); 11 | assert.equal(foo.querySelector('.bar').textContent.trim(), 'bar'); 12 | assert.equal(find('.foo').querySelector('.bar').textContent.trim(), 'bar'); 13 | assert.equal(find('.foo .bar').textContent.trim(), 'bar'); 14 | assert.equal(foo.querySelectorAll('.bar').length, 2); 15 | assert.equal(find('.foo').querySelectorAll('.bar').length, 2); 16 | assert.equal(findAll('.foo .bar').length, 2); 17 | 18 | await click(foo.querySelector('button')); 19 | await click('button', { shiftKey: true }); 20 | await click(foo.querySelector('button'), { shiftKey: true }); 21 | }); 22 | -------------------------------------------------------------------------------- /transforms/native-dom/__testfixtures__/double-import.input.js: -------------------------------------------------------------------------------- 1 | import { click, currentURL } from 'ember-native-dom-helpers'; 2 | import { find, visit } from 'ember-native-dom-helpers'; 3 | 4 | test('visiting /foo', async function(assert) { 5 | await visit('/foo'); 6 | await click('.foo'); 7 | assert.ok(find('.foo')); 8 | assert.ok(currentURL()); 9 | }); 10 | -------------------------------------------------------------------------------- /transforms/native-dom/__testfixtures__/double-import.output.js: -------------------------------------------------------------------------------- 1 | import { click, currentURL, find, visit } from '@ember/test-helpers'; 2 | 3 | test('visiting /foo', async function(assert) { 4 | await visit('/foo'); 5 | await click('.foo'); 6 | assert.ok(find('.foo')); 7 | assert.ok(currentURL()); 8 | }); 9 | -------------------------------------------------------------------------------- /transforms/native-dom/__testfixtures__/integration.input.js: -------------------------------------------------------------------------------- 1 | import { 2 | click, 3 | find, 4 | findAll, 5 | findWithAssert, 6 | fillIn, 7 | focus, 8 | blur, 9 | triggerEvent, 10 | keyEvent, 11 | scrollTo, 12 | selectFiles, 13 | waitFor, 14 | waitUntil, 15 | } from 'ember-native-dom-helpers'; 16 | import { moduleForComponent, test } from 'ember-qunit'; 17 | import hbs from 'htmlbars-inline-precompile'; 18 | 19 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 20 | integration: true 21 | }); 22 | 23 | test('it renders', async function(assert) { 24 | this.render(hbs`{{foo-bar}}`); 25 | 26 | await click('.foo', {}); 27 | assert.equal(find('.foo').id, 'foo'); 28 | await fillIn('.foo input', 'bar'); 29 | await blur('.foo input'); 30 | assert.equal(find('.foo').textContent.trim(), 'foo'); 31 | }); 32 | 33 | test('it renders again', function(assert) { 34 | this.render(hbs`{{foo-bar}}`); 35 | 36 | let selector = '.foo input'; 37 | assert.equal(findAll(selector).length, 1); 38 | assert.equal(find(selector).value, 'foo'); 39 | assert.ok(find('.foo').classList.contains('selected')); 40 | }); 41 | 42 | test('and again', async function(assert) { 43 | this.render(hbs`{{foo-bar}}`); 44 | 45 | await tap('foo'); 46 | let el = findWithAssert('.foo input'); 47 | 48 | await fillIn(el, value); 49 | await triggerEvent('.foo input', 'change'); 50 | await keyEvent('bar', 'keypress', 13, modifiers); 51 | 52 | await focus('.foo input'); 53 | await blur('.foo input'); 54 | 55 | assert.ok(findAll('.baz')[1].classList.contains('selected')); 56 | }); 57 | 58 | test('and yet again', async function(assert) { 59 | this.render(hbs`{{foo-bar}}`); 60 | 61 | await scrollTo(document, 10, 20); 62 | await selectFiles('input[type=file]', [new Blob(['texters'], { type: 'plain/text' })]); 63 | await waitUntil(() => find('.foo.active')); 64 | await waitFor('.bar.selected'); 65 | assert.ok(true); 66 | }); 67 | -------------------------------------------------------------------------------- /transforms/native-dom/__testfixtures__/integration.output.js: -------------------------------------------------------------------------------- 1 | import { 2 | click, 3 | find, 4 | findAll, 5 | fillIn, 6 | focus, 7 | blur, 8 | triggerEvent, 9 | triggerKeyEvent, 10 | waitFor, 11 | waitUntil, 12 | } from '@ember/test-helpers'; 13 | 14 | import { findWithAssert, scrollTo, selectFiles } from 'ember-native-dom-helpers'; 15 | import { moduleForComponent, test } from 'ember-qunit'; 16 | import hbs from 'htmlbars-inline-precompile'; 17 | 18 | moduleForComponent('foo-bar', 'Integration | Component | foo bar', { 19 | integration: true 20 | }); 21 | 22 | test('it renders', async function(assert) { 23 | this.render(hbs`{{foo-bar}}`); 24 | 25 | await click('.foo', {}); 26 | assert.equal(find('.foo').id, 'foo'); 27 | await fillIn('.foo input', 'bar'); 28 | await blur('.foo input'); 29 | assert.equal(find('.foo').textContent.trim(), 'foo'); 30 | }); 31 | 32 | test('it renders again', function(assert) { 33 | this.render(hbs`{{foo-bar}}`); 34 | 35 | let selector = '.foo input'; 36 | assert.equal(findAll(selector).length, 1); 37 | assert.equal(find(selector).value, 'foo'); 38 | assert.ok(find('.foo').classList.contains('selected')); 39 | }); 40 | 41 | test('and again', async function(assert) { 42 | this.render(hbs`{{foo-bar}}`); 43 | 44 | await tap('foo'); 45 | let el = findWithAssert('.foo input'); 46 | 47 | await fillIn(el, value); 48 | await triggerEvent('.foo input', 'change'); 49 | await triggerKeyEvent('bar', 'keypress', 13, modifiers); 50 | 51 | await focus('.foo input'); 52 | await blur('.foo input'); 53 | 54 | assert.ok(findAll('.baz')[1].classList.contains('selected')); 55 | }); 56 | 57 | test('and yet again', async function(assert) { 58 | this.render(hbs`{{foo-bar}}`); 59 | 60 | await scrollTo(document, 10, 20); 61 | await selectFiles('input[type=file]', [new Blob(['texters'], { type: 'plain/text' })]); 62 | await waitUntil(() => find('.foo.active')); 63 | await waitFor('.bar.selected'); 64 | assert.ok(true); 65 | }); 66 | -------------------------------------------------------------------------------- /transforms/native-dom/__testfixtures__/prune-import.input.js: -------------------------------------------------------------------------------- 1 | import { click } from 'ember-native-dom-helpers'; 2 | 3 | click('.foo'); 4 | -------------------------------------------------------------------------------- /transforms/native-dom/__testfixtures__/prune-import.output.js: -------------------------------------------------------------------------------- 1 | import { click } from '@ember/test-helpers'; 2 | 3 | click('.foo'); 4 | -------------------------------------------------------------------------------- /transforms/native-dom/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { addImportStatement, writeImportStatements } = require('../utils'); 5 | 6 | const importMigrations = [ 7 | 'click', 8 | 'find', 9 | 'findAll', 10 | 'fillIn', 11 | 'focus', 12 | 'blur', 13 | 'triggerEvent', 14 | ['keyEvent', 'triggerKeyEvent'], 15 | 'waitFor', 16 | 'waitUntil', 17 | 'currentURL', 18 | 'currentRouteName', 19 | 'visit', 20 | ]; 21 | const importMigrationsLookup = importMigrations.reduce((result, specifier) => { 22 | let key = specifier; 23 | let value = specifier; 24 | if (Array.isArray(specifier)) { 25 | key = specifier[0]; 26 | value = specifier[1]; 27 | } 28 | return Object.assign(result, { [key]: value }); 29 | }, {}); 30 | 31 | function renameCallee(j, root, name, newName) { 32 | root 33 | .find(j.CallExpression, { 34 | callee: { 35 | name, 36 | }, 37 | }) 38 | .forEach(({ node }) => (node.callee.name = newName)); 39 | } 40 | 41 | /** 42 | * find(selector, context) => context.querySelector(selector) 43 | * findAll(selector, context) => context.querySelectorAll(selector) 44 | * click(selector, context) => click(context.querySelector(selector)) 45 | * click(selector, context, { ...options }) => click(context.querySelector(selector), { ...options }) 46 | */ 47 | function migrateHelpersWithContext(j, root, importedName) { 48 | switch (importedName) { 49 | case 'find': 50 | root 51 | .find(j.CallExpression, { 52 | callee: { 53 | name: 'find', 54 | }, 55 | arguments: [{}, {}], 56 | }) 57 | .replaceWith(({ node }) => { 58 | let [selector, context] = node.arguments; 59 | if (selector.type === 'StringLiteral' && context.type === 'StringLiteral') { 60 | return j.callExpression(j.identifier('find'), [ 61 | j.literal(`${context.value} ${selector.value}`), 62 | ]); 63 | } 64 | return j.callExpression(j.memberExpression(context, j.identifier('querySelector')), [ 65 | selector, 66 | ]); 67 | }); 68 | break; 69 | case 'findAll': 70 | root 71 | .find(j.CallExpression, { 72 | callee: { 73 | name: 'findAll', 74 | }, 75 | arguments: [{}, {}], 76 | }) 77 | .replaceWith(({ node }) => { 78 | let [selector, context] = node.arguments; 79 | if (selector.type === 'StringLiteral' && context.type === 'StringLiteral') { 80 | return j.callExpression(j.identifier('findAll'), [ 81 | j.literal(`${context.value} ${selector.value}`), 82 | ]); 83 | } 84 | return j.callExpression(j.memberExpression(context, j.identifier('querySelectorAll')), [ 85 | selector, 86 | ]); 87 | }); 88 | break; 89 | case 'click': 90 | root 91 | .find(j.CallExpression, { 92 | callee: { 93 | name: 'click', 94 | }, 95 | arguments: [{}, {}], // matches 2 or 3 arguments 96 | }) 97 | .replaceWith(({ node }) => { 98 | let [selector, context, options] = node.arguments; 99 | if (context.type === 'ObjectExpression') { 100 | // click(selector, { ...options }) 101 | return node; 102 | } 103 | if (selector.type === 'StringLiteral' && context.type === 'StringLiteral') { 104 | return j.callExpression(j.identifier('click'), [ 105 | j.literal(`${context.value} ${selector.value}`), 106 | ]); 107 | } 108 | return j.callExpression( 109 | j.identifier('click'), 110 | [ 111 | j.callExpression(j.memberExpression(context, j.identifier('querySelector')), [ 112 | selector, 113 | ]), 114 | options, 115 | ].filter(Boolean) 116 | ); 117 | }); 118 | break; 119 | } 120 | } 121 | 122 | /** 123 | * Transform imports from ember-native-dom-helpers to @ember/test-helpers 124 | * 125 | * @param file 126 | * @param api 127 | * @returns {*|string} 128 | */ 129 | function transform(file, api) { 130 | let source = file.source; 131 | let j = getParser(api); 132 | let root = j(source); 133 | 134 | let nativeDomImportStatements = root.find(j.ImportDeclaration, { 135 | source: { value: 'ember-native-dom-helpers' }, 136 | }); 137 | if (nativeDomImportStatements.length === 0) { 138 | return root.toSource({ quote: 'single' }); 139 | } 140 | 141 | let newImports = []; 142 | 143 | nativeDomImportStatements.forEach((importStatement) => { 144 | let oldSpecifiers = importStatement.get('specifiers'); 145 | 146 | let newSpecifiers = []; 147 | oldSpecifiers.each(({ node: specifier }) => { 148 | let importedName = specifier.imported.name; 149 | if (importedName in importMigrationsLookup) { 150 | let mappedName = importMigrationsLookup[importedName]; 151 | // @todo local != imported 152 | // let localName = specifier.local.name; 153 | newImports.push(mappedName); 154 | if (importedName !== mappedName) { 155 | renameCallee(j, root, importedName, mappedName); 156 | } 157 | migrateHelpersWithContext(j, root, importedName); 158 | } else { 159 | newSpecifiers.push(specifier); 160 | } 161 | }); 162 | 163 | if (newSpecifiers.length > 0) { 164 | oldSpecifiers.replace(newSpecifiers); 165 | } else { 166 | importStatement.prune(); 167 | } 168 | }); 169 | 170 | addImportStatement(newImports); 171 | writeImportStatements(j, root); 172 | return root.toSource({ quote: 'single' }); 173 | } 174 | 175 | module.exports = transform; 176 | -------------------------------------------------------------------------------- /transforms/native-dom/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { runTransformTest } = require('codemod-cli'); 4 | 5 | runTransformTest({ 6 | type: 'jscodeshift', 7 | name: 'native-dom', 8 | }); 9 | -------------------------------------------------------------------------------- /transforms/this-render-migration/README.md: -------------------------------------------------------------------------------- 1 | # this-render-migration 2 | This codemod transform is to replace deprecated this.render() with render() from '@ember/test-helpers' package 3 | 4 | ## Usage 5 | 6 | ``` 7 | npx ember-test-helpers-codemod this-render-migration path/of/files/ or/some**/*glob.js 8 | 9 | # or 10 | 11 | yarn global add ember-test-helpers-codemod 12 | ember-test-helpers-codemod this-render-migration path/of/files/ or/some**/*glob.js 13 | ``` 14 | 15 | ## Input / Output 16 | 17 | 18 | * [basic](#basic) 19 | * [has-no-ember-test-helpers-import](#has-no-ember-test-helpers-import) 20 | 21 | 22 | 23 | --- 24 | **basic** 25 | 26 | **Input** ([basic.input.js](transforms/this-render-migration/__testfixtures__/basic.input.js)): 27 | ```js 28 | import { click } from '@ember/test-helpers'; 29 | 30 | test('It handles switching selected option on click and fires onSelect event', async function(assert) { 31 | this.onSelectMock = this.sandbox.stub(); 32 | await this.render(hbs` 33 | 34 | 35 | `); 36 | }) 37 | 38 | ``` 39 | 40 | **Output** ([basic.input.js](transforms/this-render-migration/__testfixtures__/basic.output.js)): 41 | ```js 42 | import { click, render } from '@ember/test-helpers'; 43 | 44 | test('It handles switching selected option on click and fires onSelect event', async function(assert) { 45 | this.onSelectMock = this.sandbox.stub(); 46 | await render(hbs` 47 | 48 | 49 | `); 50 | }) 51 | ``` 52 | --- 53 | **has-no-ember-test-helpers-import** 54 | 55 | **Input** ([has-no-ember-test-helpers-import.input.js](transforms/this-render-migration/__testfixtures__/has-no-ember-test-helpers-import.input.js)): 56 | ```js 57 | test('It handles switching selected option on click and fires onSelect event', async function(assert) { 58 | this.onSelectMock = this.sandbox.stub(); 59 | await this.render(hbs` 60 | 61 | 62 | `); 63 | }) 64 | 65 | ``` 66 | 67 | **Output** ([has-no-ember-test-helpers-import.input.js](transforms/this-render-migration/__testfixtures__/has-no-ember-test-helpers-import.output.js)): 68 | ```js 69 | import { render } from '@ember/test-helpers'; 70 | test('It handles switching selected option on click and fires onSelect event', async function(assert) { 71 | this.onSelectMock = this.sandbox.stub(); 72 | await render(hbs` 73 | 74 | 75 | `); 76 | }) 77 | 78 | ``` 79 | -------------------------------------------------------------------------------- /transforms/this-render-migration/__testfixtures__/basic.input.js: -------------------------------------------------------------------------------- 1 | import { click } from '@ember/test-helpers'; 2 | 3 | test('It handles switching selected option on click and fires onSelect event', async function(assert) { 4 | this.onSelectMock = this.sandbox.stub(); 5 | await this.render(hbs` 6 | 7 | 8 | `); 9 | }) 10 | -------------------------------------------------------------------------------- /transforms/this-render-migration/__testfixtures__/basic.output.js: -------------------------------------------------------------------------------- 1 | import { click, render } from '@ember/test-helpers'; 2 | 3 | test('It handles switching selected option on click and fires onSelect event', async function(assert) { 4 | this.onSelectMock = this.sandbox.stub(); 5 | await render(hbs` 6 | 7 | 8 | `); 9 | }) 10 | -------------------------------------------------------------------------------- /transforms/this-render-migration/__testfixtures__/has-no-ember-test-helpers-import.input.js: -------------------------------------------------------------------------------- 1 | test('It handles switching selected option on click and fires onSelect event', async function(assert) { 2 | this.onSelectMock = this.sandbox.stub(); 3 | await this.render(hbs` 4 | 5 | 6 | `); 7 | }) 8 | -------------------------------------------------------------------------------- /transforms/this-render-migration/__testfixtures__/has-no-ember-test-helpers-import.output.js: -------------------------------------------------------------------------------- 1 | import { render } from '@ember/test-helpers'; 2 | test('It handles switching selected option on click and fires onSelect event', async function(assert) { 3 | this.onSelectMock = this.sandbox.stub(); 4 | await render(hbs` 5 | 6 | 7 | `); 8 | }) 9 | -------------------------------------------------------------------------------- /transforms/this-render-migration/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { getParser } = require('codemod-cli').jscodeshift; 4 | const { addImportStatement, writeImportStatements } = require('../utils'); 5 | 6 | module.exports = function transformer(file, api) { 7 | const j = getParser(api); 8 | const root = j(file.source); 9 | 10 | /** 11 | * Replace deprecated this.render() with render() from '@ember/test-helpers' package 12 | */ 13 | function transform() { 14 | root 15 | .find(j.CallExpression, { 16 | callee: { 17 | type: 'MemberExpression', 18 | object: { 19 | type: 'ThisExpression', 20 | }, 21 | property: { 22 | type: 'Identifier', 23 | name: 'render', 24 | }, 25 | }, 26 | }) 27 | .replaceWith((path) => { 28 | let oldCallExpressionArguments = path.node.arguments; 29 | 30 | return j.callExpression(j.identifier('render'), oldCallExpressionArguments); 31 | }); 32 | 33 | let newImports = ['render']; 34 | 35 | addImportStatement(newImports); 36 | writeImportStatements(j, root); 37 | } 38 | 39 | transform(); 40 | 41 | return root.toSource({ 42 | quote: 'single', 43 | trailingComma: true, 44 | }); 45 | }; 46 | -------------------------------------------------------------------------------- /transforms/this-render-migration/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { runTransformTest } = require('codemod-cli'); 4 | 5 | runTransformTest({ 6 | type: 'jscodeshift', 7 | name: 'this-render-migration', 8 | }); 9 | -------------------------------------------------------------------------------- /transforms/update-triggerevent-file-param/README.md: -------------------------------------------------------------------------------- 1 | # update-triggerevent-file-param 2 | A transform to update param in `triggerEvent` from `[ file ]` to `{ files: [ file ] }` 3 | 4 | ## Usage 5 | 6 | ``` 7 | npx ember-test-helpers-codemod update-triggerevent-file-param path/of/files/ or/some**/*glob.js 8 | 9 | # or 10 | 11 | yarn global add ember-test-helpers-codemod 12 | ember-test-helpers-codemod update-triggerevent-file-param path/of/files/ or/some**/*glob.js 13 | ``` 14 | 15 | ## Input / Output 16 | 17 | 18 | * [basic](#basic) 19 | 20 | 21 | 22 | --- 23 | **basic** 24 | 25 | **Input** ([basic.input.js](transforms/update-triggerevent-file-param/__testfixtures__/basic.input.js)): 26 | ```js 27 | import { triggerEvent } from '@ember/test-helpers'; 28 | 29 | test('test', async function(assert) { 30 | await triggerEvent('[data-test-file-upload-button__input]', 'change', [file]); 31 | await triggerEvent('[data-test-file-upload-button__input]', 'change', []); 32 | }); 33 | 34 | ``` 35 | 36 | **Output** ([basic.input.js](transforms/update-triggerevent-file-param/__testfixtures__/basic.output.js)): 37 | ```js 38 | import { triggerEvent } from '@ember/test-helpers'; 39 | 40 | test('test', async function(assert) { 41 | await triggerEvent('[data-test-file-upload-button__input]', 'change', { 42 | files: [file] 43 | }); 44 | await triggerEvent('[data-test-file-upload-button__input]', 'change', { 45 | files: [] 46 | }); 47 | }); 48 | 49 | ``` 50 | -------------------------------------------------------------------------------- /transforms/update-triggerevent-file-param/__testfixtures__/basic.input.js: -------------------------------------------------------------------------------- 1 | import { triggerEvent } from '@ember/test-helpers'; 2 | 3 | test('test', async function(assert) { 4 | await triggerEvent('[data-test-file-upload-button__input]', 'change', [file]); 5 | await triggerEvent('[data-test-file-upload-button__input]', 'change', []); 6 | }); 7 | -------------------------------------------------------------------------------- /transforms/update-triggerevent-file-param/__testfixtures__/basic.output.js: -------------------------------------------------------------------------------- 1 | import { triggerEvent } from '@ember/test-helpers'; 2 | 3 | test('test', async function(assert) { 4 | await triggerEvent('[data-test-file-upload-button__input]', 'change', { 5 | files: [file] 6 | }); 7 | await triggerEvent('[data-test-file-upload-button__input]', 'change', { 8 | files: [] 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /transforms/update-triggerevent-file-param/index.js: -------------------------------------------------------------------------------- 1 | const { getParser } = require('codemod-cli').jscodeshift; 2 | 3 | module.exports = function transformer(file, api) { 4 | const j = getParser(api); 5 | const root = j(file.source); 6 | 7 | /** 8 | * A transform to update param in `triggerEvent` from `[ file ]` to `{ files: [ file ] }` 9 | */ 10 | function transform() { 11 | root 12 | .find(j.CallExpression, { 13 | callee: { 14 | name: 'triggerEvent', 15 | }, 16 | }) 17 | .find(j.ArrayExpression) 18 | .replaceWith((path) => { 19 | // make sure we just modify the arrayExpression which is the param of triggerEvent call expression 20 | if ( 21 | path.parent.node.type === 'CallExpression' && 22 | path.parent.node.callee.name === 'triggerEvent' 23 | ) { 24 | return j.objectExpression([j.property('init', j.identifier('files'), path.node)]); 25 | } else return path.node; 26 | }); 27 | } 28 | 29 | transform(); 30 | 31 | return root.toSource({ 32 | quote: 'single', 33 | trailingComma: false, 34 | }); 35 | }; 36 | -------------------------------------------------------------------------------- /transforms/update-triggerevent-file-param/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { runTransformTest } = require('codemod-cli'); 4 | 5 | runTransformTest({ 6 | type: 'jscodeshift', 7 | name: 'update-triggerevent-file-param', 8 | }); 9 | -------------------------------------------------------------------------------- /transforms/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const jqExtensions = [ 4 | /:eq/, 5 | /:even/, 6 | /:odd/, 7 | /:contains\(/, 8 | /:has\(/, 9 | /:animated/, 10 | /:checkbox/, 11 | /:file/, 12 | /:first(?!-child)/, 13 | /:gt\(/, 14 | /:header/, 15 | /:hidden/, 16 | /:image/, 17 | /:input/, 18 | /:last(?!-child)/, 19 | /:lt\(/, 20 | /:parent/, 21 | /:password/, 22 | /:radio/, 23 | /:reset/, 24 | /:selected/, 25 | /:submit/, 26 | /:text/, 27 | /:visible/, 28 | ]; 29 | 30 | const supportedJqExtensions = [/.+:eq/, /.+:selected/]; 31 | 32 | const tailEqRegex = /:eq\(\d+\)$/; 33 | const selectedRegex = /:selected/; 34 | 35 | // Collects all statements that need to be imported. Gets flushed when writeImportStatemtns is called. 36 | let _statementsToImport = new Set(); 37 | 38 | /** 39 | * Check of the CSS selector string contains some jQuery specific parts 40 | * 41 | * @param {string} string 42 | * @param {boolean} excludeSupported 43 | * @returns {boolean} 44 | */ 45 | function containsJQuerySelectorExtension(string, excludeSupported = true) { 46 | return ( 47 | jqExtensions.some((regex) => string.match(regex)) && 48 | (!excludeSupported || !supportedJqExtensions.some((regex) => string.match(regex))) 49 | ); 50 | } 51 | 52 | /** 53 | * Check if given node is a `this.$(selector)` expression. 54 | * 55 | * Will return false if that selector is a string literal or variable reference and contains jQuery specific 56 | * (not standards compliant) selectors that cannot be transformed 57 | * 58 | * @param j jscodeshift API 59 | * @param node AST node 60 | * @param path NodePath 61 | * @returns {boolean} 62 | */ 63 | function isJQuerySelectExpression(j, node, path) { 64 | if ( 65 | j.CallExpression.check(node) && 66 | j.MemberExpression.check(node.callee) && 67 | j.ThisExpression.check(node.callee.object) && 68 | j.Identifier.check(node.callee.property) && 69 | node.callee.property.name === '$' 70 | ) { 71 | let hasNoArgs = node.arguments.length === 0; 72 | let isLiteralSelector = 73 | j.Literal.check(node.arguments[0]) && 74 | typeof node.arguments[0].value === 'string' && 75 | !containsJQuerySelectorExtension(node.arguments[0].value); 76 | 77 | if (hasNoArgs || isLiteralSelector) { 78 | return true; 79 | } 80 | 81 | if (j.Identifier.check(node.arguments[0])) { 82 | let name = node.arguments[0].name; 83 | let definingScope = path.scope.lookup(name); 84 | 85 | if (!definingScope) return false; 86 | let bindings = definingScope.getBindings()[name]; 87 | if (!bindings) return false; 88 | 89 | let parent = bindings[0].parent; 90 | return ( 91 | j.VariableDeclarator.check(parent.node) && 92 | j.Literal.check(parent.node.init) && 93 | typeof parent.node.init.value === 'string' && 94 | !containsJQuerySelectorExtension(parent.node.init.value, false) 95 | ); 96 | } 97 | } 98 | return false; 99 | } 100 | 101 | /** 102 | * Check if `node` is a `find(selector)` expression 103 | * 104 | * @param j 105 | * @param node 106 | * @returns {*|boolean} 107 | */ 108 | function isFindExpression(j, node) { 109 | return ( 110 | j.CallExpression.check(node) && j.Identifier.check(node.callee) && node.callee.name === 'find' 111 | ); 112 | } 113 | 114 | /** 115 | * Transform jQuery specific selectors to a standards-compliant version 116 | * 117 | * @param j jscodeshift API 118 | * @param selector 119 | * @returns {*} 120 | */ 121 | function migrateSelector(j, selector) { 122 | if (j.Literal.check(selector) && typeof selector.value === 'string') { 123 | let string = selector.value; 124 | 125 | if (selectedRegex.test(string)) { 126 | selector.value = selector.value.replace(selectedRegex, ':checked'); 127 | } 128 | 129 | // When handling a special-case selector, return early. 130 | 131 | // Transform tail-eq selector to a find all 132 | if (tailEqRegex.test(string)) { 133 | let [, query, eqIndex] = string.match(/(.+?):eq\((\d+)\)$/); 134 | selector.value = query; 135 | if (eqIndex === '0') { 136 | // findAll('*')[0] === find('*') 137 | addImportStatement(['find']); 138 | return createFindExpression(j, [selector]); 139 | } else { 140 | addImportStatement(['findAll']); 141 | return createArraySubscriptExpression(j, createFindAllExpression(j, [selector]), +eqIndex); 142 | } 143 | } 144 | } 145 | return selector; 146 | } 147 | 148 | /** 149 | * Create a `find(selector)` expression 150 | * 151 | * @param j jscodeshift API 152 | * @param args function arguments 153 | * @returns {*} 154 | */ 155 | function createFindExpression(j, args) { 156 | args = args.length > 0 ? args.map((s) => migrateSelector(j, s)) : [j.literal('*')]; 157 | 158 | // Avoid nesting find calls 159 | let isFindCallExpression = 160 | args.length === 1 && 161 | j.CallExpression.check(args[0]) && 162 | j.Identifier.check(args[0].callee) && 163 | args[0].callee.name === 'find'; 164 | 165 | if (isFindCallExpression) { 166 | return args[0]; 167 | } 168 | 169 | return j.callExpression(j.identifier('find'), args); 170 | } 171 | 172 | /** 173 | * Create a `findAll(selector)` expression 174 | * 175 | * @param j jscodeshift API 176 | * @param args function arguments 177 | * @returns {*} 178 | */ 179 | function createFindAllExpression(j, args, fileRoot) { 180 | args = args.length > 0 ? args.map((s) => migrateSelector(j, s, fileRoot)) : [j.literal('*')]; 181 | 182 | // Avoid nesting findAll calls 183 | let isFindAllCallExpression = 184 | args.length === 1 && 185 | j.CallExpression.check(args[0]) && 186 | j.Identifier.check(args[0].callee) && 187 | args[0].callee.name === 'findAll'; 188 | 189 | let isFindAllMemberExpression = 190 | args.length === 1 && 191 | j.MemberExpression.check(args[0]) && 192 | j.Identifier.check(args[0].object.callee) && 193 | args[0].object.callee.name === 'findAll'; 194 | 195 | if (isFindAllCallExpression || isFindAllMemberExpression) { 196 | return args[0]; 197 | } 198 | 199 | return j.callExpression(j.identifier('findAll'), args); 200 | } 201 | 202 | /** 203 | * Create a `this.element.querySelector(selector)` expression 204 | * 205 | * @param j jscodeshift API 206 | * @param args function arguments 207 | * @returns {*} 208 | */ 209 | function createQuerySelectorExpression(j, args) { 210 | args = args.length > 0 ? args.map((s) => migrateSelector(j, s)) : [j.literal('*')]; 211 | 212 | // Avoid nesting find calls 213 | let isQuerySelectorCallExpression = 214 | args.length === 1 && 215 | j.CallExpression.check(args[0]) && 216 | j.MemberExpression.check(args[0].callee) && 217 | j.MemberExpression.check(args[0].callee.object) && 218 | // && j.ThisExpression.check(args[0].callee.object.object) 219 | args[0].callee.object.property.name === 'element' && 220 | args[0].callee.property.name === 'querySelector'; 221 | 222 | if (isQuerySelectorCallExpression) { 223 | return args[0]; 224 | } 225 | 226 | return j.callExpression( 227 | j.memberExpression( 228 | j.memberExpression(j.thisExpression(), j.identifier('element')), 229 | j.identifier('querySelector') 230 | ), 231 | args 232 | ); 233 | } 234 | 235 | /** 236 | * Create a `this.element.querySelectorAll(selector)` expression 237 | * 238 | * @param j jscodeshift API 239 | * @param args function arguments 240 | * @returns {*} 241 | */ 242 | function createQuerySelectorAllExpression(j, args, fileRoot) { 243 | args = args.length > 0 ? args.map((s) => migrateSelector(j, s, fileRoot)) : [j.literal('*')]; 244 | 245 | // Avoid nesting querySelector calls 246 | let isQSA = args.length === 1 && isQuerySelectorAllCallExpression(j, args[0]); 247 | 248 | let isQSAMemberExpression = 249 | args.length === 1 && 250 | j.MemberExpression.check(args[0]) && 251 | isQuerySelectorAllCallExpression(j, args[0].object); 252 | 253 | if (isQSA || isQSAMemberExpression) { 254 | return args[0]; 255 | } 256 | 257 | return j.callExpression( 258 | j.memberExpression( 259 | j.memberExpression(j.thisExpression(), j.identifier('element')), 260 | j.identifier('querySelectorAll') 261 | ), 262 | args 263 | ); 264 | } 265 | 266 | function isQuerySelectorAllCallExpression(j, node) { 267 | return ( 268 | j.CallExpression.check(node) && 269 | j.MemberExpression.check(node.callee) && 270 | j.MemberExpression.check(node.callee.object) && 271 | // && j.ThisExpression.check(node.callee.object.object) 272 | node.callee.object.property.name === 'element' && 273 | node.callee.property.name === 'querySelectorAll' 274 | ); 275 | } 276 | 277 | /** 278 | * Create `await click(selector)` expression 279 | * @param j 280 | * @param args 281 | * @returns {*} 282 | */ 283 | function createClickExpression(j, args) { 284 | args = args.map((s) => migrateSelector(j, s)); 285 | 286 | return j.awaitExpression(j.callExpression(j.identifier('click'), args)); 287 | } 288 | 289 | /** 290 | * Create a `triggerEvent(selector, eventName) expression 291 | * 292 | * @param j jscodeshift API 293 | * @param selector selector arguments 294 | * @param eventName 295 | * @returns {*} 296 | */ 297 | function createTriggerExpression(j, selector, eventName) { 298 | let triggerExpression = j.callExpression(j.identifier('triggerEvent'), [ 299 | migrateSelector(j, selector), 300 | eventName, 301 | ]); 302 | return j.awaitExpression(triggerExpression); 303 | } 304 | 305 | /** 306 | * Create a `find(selector).prop` expression 307 | * 308 | * @param j jscodeshift API 309 | * @param selector selector arguments 310 | * @param prop property 311 | * @returns {*} 312 | */ 313 | function createPropExpression(j, findArgs, prop) { 314 | return j.memberExpression(createFindExpression(j, findArgs), j.identifier(prop)); 315 | } 316 | 317 | function createArraySubscriptExpression(j, expression, index) { 318 | return j.memberExpression(expression, j.literal(index)); 319 | } 320 | 321 | /** 322 | * Create `await focus(selector)` expression 323 | * @param j 324 | * @param selector 325 | * @returns {*} 326 | */ 327 | function createFocusExpression(j, selector) { 328 | return j.awaitExpression(j.callExpression(j.identifier('focus'), [migrateSelector(j, selector)])); 329 | } 330 | 331 | /** 332 | * Create `await focus(selector)` expression 333 | * @param j 334 | * @param selector 335 | * @returns {*} 336 | */ 337 | function createBlurExpression(j, selector) { 338 | return j.awaitExpression(j.callExpression(j.identifier('blur'), [migrateSelector(j, selector)])); 339 | } 340 | 341 | /** 342 | * Adds (one or more) named imports to a private import statement collection. 343 | * To write the import statements to a file, use writeImportStatements. 344 | * 345 | * @param j 346 | * @param {array} imports 347 | */ 348 | function addImportStatement(imports) { 349 | imports.forEach((method) => _statementsToImport.add(method)); 350 | } 351 | 352 | /** 353 | * Adds all collected named imports to an (existing or to be created) `import { namedImport } from '@ember/test-helpers'; 354 | * To add named imports to the collection, use addImportStatement 355 | * 356 | * @param j 357 | * @param root 358 | */ 359 | function writeImportStatements(j, root) { 360 | if (_statementsToImport.size > 0) { 361 | let body = root.get().value.program.body; 362 | let importStatement = root.find(j.ImportDeclaration, { 363 | source: { value: '@ember/test-helpers' }, 364 | }); 365 | 366 | let actuallyNeedsImport = Array.from(_statementsToImport).filter((methodName) => { 367 | return ( 368 | root.find(j.CallExpression, { 369 | callee: { 370 | name: methodName, 371 | }, 372 | }).length > 0 373 | ); 374 | }); 375 | 376 | if (actuallyNeedsImport.length === 0) { 377 | return; 378 | } 379 | 380 | if (importStatement.length === 0) { 381 | importStatement = createImportStatement( 382 | j, 383 | '@ember/test-helpers', 384 | 'default', 385 | actuallyNeedsImport 386 | ); 387 | body.unshift(importStatement); 388 | } else { 389 | let existingSpecifiers = importStatement.get('specifiers'); 390 | 391 | actuallyNeedsImport.forEach((name) => { 392 | if (existingSpecifiers.filter((exSp) => exSp.value.imported.name === name).length === 0) { 393 | existingSpecifiers.push(j.importSpecifier(j.identifier(name))); 394 | } 395 | }); 396 | } 397 | } 398 | 399 | _statementsToImport = new Set(); 400 | } 401 | 402 | /** 403 | * Create an ES6 module import statement 404 | * 405 | * @param j 406 | * @param source 407 | * @param imported 408 | * @param local 409 | * @returns {*} 410 | */ 411 | function createImportStatement(j, source, imported, local) { 412 | let declaration, variable, idIdentifier, nameIdentifier; 413 | 414 | // if no variable name, return `import 'jquery'` 415 | if (!local) { 416 | declaration = j.importDeclaration([], j.literal(source)); 417 | return declaration; 418 | } 419 | 420 | // multiple variable names indicates a destructured import 421 | if (Array.isArray(local)) { 422 | let variableIds = local.map(function (v) { 423 | return j.importSpecifier(j.identifier(v), j.identifier(v)); 424 | }); 425 | 426 | declaration = j.importDeclaration(variableIds, j.literal(source)); 427 | } else { 428 | // else returns `import $ from 'jquery'` 429 | nameIdentifier = j.identifier(local); //import var name 430 | variable = j.importDefaultSpecifier(nameIdentifier); 431 | 432 | // if propName, use destructuring `import {pluck} from 'underscore'` 433 | if (imported && imported !== 'default') { 434 | idIdentifier = j.identifier(imported); 435 | variable = j.importSpecifier(idIdentifier, nameIdentifier); // if both are same, one is dropped... 436 | } 437 | 438 | declaration = j.importDeclaration([variable], j.literal(source)); 439 | } 440 | 441 | return declaration; 442 | } 443 | 444 | /** 445 | * Find the first parent function that contains the given path object 446 | * 447 | * @param j jscodeshift API 448 | * @param path AST path 449 | * @returns {*} 450 | */ 451 | function findParentFunction(j, path) { 452 | while ((path = path.parent)) { 453 | if ( 454 | (j.FunctionExpression.check(path.node) && !isAndThenCall(j, path)) || 455 | j.FunctionDeclaration.check(path.node) || 456 | (j.ArrowFunctionExpression.check(path.node) && !isAndThenCall(j, path)) 457 | ) { 458 | return path; 459 | } 460 | } 461 | } 462 | 463 | /** 464 | * Check if path is the function of a `andThen(function() {})` expression 465 | * @param j 466 | * @param path 467 | * @returns {*|boolean} 468 | */ 469 | function isAndThenCall(j, path) { 470 | let parentNode = path.parent.node; 471 | return ( 472 | (j.FunctionExpression.check(path.node) || j.ArrowFunctionExpression.check(path.node)) && 473 | j.CallExpression.check(parentNode) && 474 | j.Identifier.check(parentNode.callee) && 475 | parentNode.callee.name === 'andThen' 476 | ); 477 | } 478 | 479 | /** 480 | * Finds the parent function that contains `path` and makes it `async` 481 | * 482 | * @param j jscodeshift API 483 | * @param path AST path 484 | */ 485 | function makeParentFunctionAsync(j, path) { 486 | let fn = findParentFunction(j, path); 487 | if (fn) { 488 | fn.node.async = true; 489 | } 490 | } 491 | 492 | /** 493 | * Remove calls to `andThen` and replace with inlined function body 494 | * 495 | * 496 | * @param j 497 | * @param root 498 | */ 499 | function dropAndThen(j, root) { 500 | let replacements = root 501 | .find(j.CallExpression, { callee: { name: 'andThen' } }) 502 | .map((path) => path.parent) 503 | .replaceWith(({ node }) => { 504 | let body; 505 | if (j.ExpressionStatement.check(node)) { 506 | body = node.expression.arguments[0].body; 507 | } else if (j.ReturnStatement.check(node)) { 508 | body = node.argument.arguments[0].body; 509 | } 510 | 511 | if (body) { 512 | if (j.CallExpression.check(body)) { 513 | return j.expressionStatement(body); 514 | } 515 | 516 | return body.body; 517 | } 518 | }); 519 | 520 | if (replacements.length > 0) { 521 | dropAndThen(j, replacements); 522 | } 523 | } 524 | 525 | function makeAwait(j, collection) { 526 | collection 527 | .filter(({ parent: { node } }) => j.ExpressionStatement.check(node)) 528 | .replaceWith(({ node }) => j.awaitExpression(node)) 529 | .forEach((path) => { 530 | return makeParentFunctionAsync(j, path); 531 | }); 532 | } 533 | 534 | /** 535 | * $.each's arguments are in the reverse order that Array.forEach's arguments are in. 536 | * Here we reverse the order of the args if there are two, or add the current element to the front 537 | * of the arguments array if there is only one arg. 538 | * @param {*} callBack 539 | */ 540 | function transformEachsCallbackArgs(callBack) { 541 | let eachCallBackArgs = callBack[0].params; 542 | if (eachCallBackArgs.length === 1) { 543 | eachCallBackArgs.unshift('element'); 544 | } else { 545 | eachCallBackArgs = eachCallBackArgs.reverse(); 546 | } 547 | return callBack; 548 | } 549 | 550 | module.exports = { 551 | isJQuerySelectExpression, 552 | isFindExpression, 553 | createFindExpression, 554 | createFindAllExpression, 555 | createQuerySelectorExpression, 556 | createQuerySelectorAllExpression, 557 | createClickExpression, 558 | createTriggerExpression, 559 | createPropExpression, 560 | createArraySubscriptExpression, 561 | createFocusExpression, 562 | createBlurExpression, 563 | addImportStatement, 564 | writeImportStatements, 565 | makeParentFunctionAsync, 566 | migrateSelector, 567 | dropAndThen, 568 | makeAwait, 569 | transformEachsCallbackArgs, 570 | }; 571 | --------------------------------------------------------------------------------