Repository: ember-cli/eslint-plugin-ember
Pull request #1056 (2020-12-28 13:57:00)

Implement `no-current-route-name` rule
Resolves https://github.com/ember-cli/eslint-plugin-ember/issues/1050

---

# no-current-route-name

The route name is something which is not visible to the user, so it can be
considered an implementation detail. The URL however is visible to the user, so
when writing tests it makes much more sense to assert against `currentURL()`
instead of `currentRouteName()`.

## Rule Details

This rule warns about any usage of the `currentRouteName()` test helper. 

## Examples

Examples of **incorrect** code for this rule:

```js
assert.equal(currentRouteName(), 'foo');
```

Examples of **correct** code for this rule:

```js
assert.equal(currentURL(), '/foo');
```

## Migration

* Replace `currentRouteName()` with `currentURL()` and adjust
  the assertion expectations

## References

* [currentRouteName()](https://github.com/emberjs/ember-test-helpers/blob/master/API.md#currentroutename) documentation
* [currentURL()](https://github.com/emberjs/ember-test-helpers/blob/master/API.md#currenturl) documentation



Patch:
diff --git a/README.md b/README.md
index e2c94f6e..1b010ac1 100644
--- a/README.md
+++ b/README.md
@@ -155,7 +155,6 @@ Rules are grouped by category to help you understand their purpose. Each rule ha
 | :white_check_mark: | [no-incorrect-calls-with-inline-anonymous-functions](./docs/rules/no-incorrect-calls-with-inline-anonymous-functions.md) | disallow inline anonymous functions as arguments to `debounce`, `once`, and `scheduleOnce` |
 | :white_check_mark: | [no-invalid-debug-function-arguments](./docs/rules/no-invalid-debug-function-arguments.md) | disallow usages of Ember's `assert()` / `warn()` / `deprecate()` functions that have the arguments passed in the wrong order. |
 |  | [no-restricted-service-injections](./docs/rules/no-restricted-service-injections.md) | disallow injecting certain services under certain paths |
-|  | [require-fetch-import](./docs/rules/require-fetch-import.md) | enforce explicit import for `fetch()` |
 
 ### Routes
 
@@ -184,6 +183,7 @@ Rules are grouped by category to help you understand their purpose. Each rule ha
 
 |    | Rule ID | Description |
 |:---|:--------|:------------|
+|  | [no-current-route-name](./docs/rules/no-current-route-name.md) | disallow usage of the `currentRouteName()` test helper |
 | :white_check_mark: | [no-ember-testing-in-module-scope](./docs/rules/no-ember-testing-in-module-scope.md) | disallow use of `Ember.testing` in module scope |
 | :white_check_mark: | [no-invalid-test-waiters](./docs/rules/no-invalid-test-waiters.md) | disallow incorrect usage of test waiter APIs |
 | :white_check_mark: | [no-legacy-test-waiters](./docs/rules/no-legacy-test-waiters.md) | disallow the use of the legacy test waiter APIs |
diff --git a/docs/rules/no-current-route-name.md b/docs/rules/no-current-route-name.md
new file mode 100644
index 00000000..72c0e8fa
--- /dev/null
+++ b/docs/rules/no-current-route-name.md
@@ -0,0 +1,34 @@
+# no-current-route-name
+
+The route name is something which is not visible to the user, so it can be
+considered an implementation detail. The URL however is visible to the user, so
+when writing tests it makes much more sense to assert against `currentURL()`
+instead of `currentRouteName()`.
+
+## Rule Details
+
+This rule warns about any usage of the `currentRouteName()` test helper.
+
+## Examples
+
+Examples of **incorrect** code for this rule:
+
+```js
+assert.equal(currentRouteName(), 'foo');
+```
+
+Examples of **correct** code for this rule:
+
+```js
+assert.equal(currentURL(), '/foo');
+```
+
+## Migration
+
+* Replace `currentRouteName()` with `currentURL()` and adjust
+  the assertion expectations
+
+## References
+
+* [currentRouteName()](https://github.com/emberjs/ember-test-helpers/blob/master/API.md#currentroutename) documentation
+* [currentURL()](https://github.com/emberjs/ember-test-helpers/blob/master/API.md#currenturl) documentation
diff --git a/docs/rules/require-fetch-import.md b/docs/rules/require-fetch-import.md
deleted file mode 100644
index 42c49354..00000000
--- a/docs/rules/require-fetch-import.md
+++ /dev/null
@@ -1,38 +0,0 @@
-# require-fetch-import
-
-Using `fetch()` without importing it causes the browser to use the native,
-non-wrapped `window.fetch()`. This is generally fine, but makes testing harder
-because this non-wrapped version does not have a built-in test waiter. Because
-of this it is generally better to use [ember-fetch] and explicitly
-`import fetch from 'fetch'`.
-
-## Rule Details
-
-The rule looks for `fetch()` calls and reports them as issues if no
-corresponding import declaration is found.
-
-## Examples
-
-Examples of **incorrect** code for this rule:
-
-```js
-const result = fetch('/something');
-```
-
-Examples of **correct** code for this rule:
-
-```js
-import fetch from 'fetch';
-
-const result = fetch('/something');
-```
-
-## Migration
-
-* Add `import fetch from 'fetch';` to all files that need it
-
-## References
-
-* [@ember/test-waiters](https://github.com/emberjs/ember-test-waiters) addon
-
-[ember-fetch]: https://github.com/ember-cli/ember-fetch/
diff --git a/lib/index.js b/lib/index.js
index 25aac65a..ed993ea6 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -24,6 +24,7 @@ module.exports = {
     'no-computed-properties-in-native-classes': require('./rules/no-computed-properties-in-native-classes'),
     'no-controller-access-in-routes': require('./rules/no-controller-access-in-routes'),
     'no-controllers': require('./rules/no-controllers'),
+    'no-current-route-name': require('./rules/no-current-route-name'),
     'no-deeply-nested-dependent-keys-with-each': require('./rules/no-deeply-nested-dependent-keys-with-each'),
     'no-duplicate-dependent-keys': require('./rules/no-duplicate-dependent-keys'),
     'no-ember-super-in-es-classes': require('./rules/no-ember-super-in-es-classes'),
@@ -74,7 +75,6 @@ module.exports = {
     'prefer-ember-test-helpers': require('./rules/prefer-ember-test-helpers'),
     'require-computed-macros': require('./rules/require-computed-macros'),
     'require-computed-property-dependencies': require('./rules/require-computed-property-dependencies'),
-    'require-fetch-import': require('./rules/require-fetch-import'),
     'require-return-from-computed': require('./rules/require-return-from-computed'),
     'require-super-in-lifecycle-hooks': require('./rules/require-super-in-lifecycle-hooks'),
     'require-tagless-components': require('./rules/require-tagless-components'),
diff --git a/lib/rules/no-current-route-name.js b/lib/rules/no-current-route-name.js
new file mode 100644
index 00000000..01d3989a
--- /dev/null
+++ b/lib/rules/no-current-route-name.js
@@ -0,0 +1,44 @@
+'use strict';
+
+const ERROR_MESSAGE = 'Use currentURL() instead of currentRouteName()';
+
+module.exports = {
+  meta: {
+    type: 'suggestion',
+    docs: {
+      description: 'disallow usage of the `currentRouteName()` test helper',
+      category: 'Testing',
+      recommended: false,
+      url:
+        'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/no-current-route-name.md',
+    },
+    fixable: null,
+    schema: [],
+  },
+
+  ERROR_MESSAGE,
+
+  create(context) {
+    const importAliases = [];
+
+    return {
+      ImportSpecifier(node) {
+        const { imported, local } = node;
+        if (
+          imported.type === 'Identifier' &&
+          imported.name === 'currentRouteName' &&
+          local.type === 'Identifier'
+        ) {
+          importAliases.push(node.local.name);
+        }
+      },
+
+      CallExpression(node) {
+        const { callee } = node;
+        if (callee.type === 'Identifier' && importAliases.includes(callee.name)) {
+          context.report(node, ERROR_MESSAGE);
+        }
+      },
+    };
+  },
+};
diff --git a/lib/rules/require-fetch-import.js b/lib/rules/require-fetch-import.js
deleted file mode 100644
index 30501153..00000000
--- a/lib/rules/require-fetch-import.js
+++ /dev/null
@@ -1,38 +0,0 @@
-'use strict';
-
-const { ReferenceTracker } = require('eslint-utils');
-
-const ERROR_MESSAGE = 'Explicitly import `fetch` instead of using `window.fetch`';
-
-module.exports = {
-  meta: {
-    type: 'suggestion',
-    docs: {
-      description: 'enforce explicit import for `fetch()`',
-      category: 'Miscellaneous',
-      recommended: false,
-      url:
-        'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/require-fetch-import.md',
-    },
-    fixable: null,
-    schema: [],
-  },
-
-  ERROR_MESSAGE,
-
-  create(context) {
-    return {
-      'Program:exit'() {
-        const tracker = new ReferenceTracker(context.getScope());
-
-        const traceMap = {
-          fetch: { [ReferenceTracker.CALL]: true },
-        };
-
-        for (const { node } of tracker.iterateGlobalReferences(traceMap)) {
-          context.report(node, ERROR_MESSAGE);
-        }
-      },
-    };
-  },
-};


Test patch:
diff --git a/tests/lib/rules/no-current-route-name.js b/tests/lib/rules/no-current-route-name.js
new file mode 100644
index 00000000..a1472584
--- /dev/null
+++ b/tests/lib/rules/no-current-route-name.js
@@ -0,0 +1,51 @@
+'use strict';
+
+const rule = require('../../../lib/rules/no-current-route-name');
+const RuleTester = require('eslint').RuleTester;
+
+const { ERROR_MESSAGE } = rule;
+
+const ruleTester = new RuleTester({
+  parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+});
+
+ruleTester.run('no-current-route-name', rule, {
+  valid: [
+    "assert.equal(currentURL(), '/foo');",
+    "assert.equal(currentRouteName(), '/foo');",
+
+    `
+      import { currentURL } from '@ember/test-helpers';
+
+      assert.equal(currentURL(), '/foo');
+    `,
+
+    // who knows...
+    `
+      import { currentURL as currentRouteName } from '@ember/test-helpers';
+
+      assert.equal(currentRouteName(), '/foo');
+    `,
+  ],
+
+  invalid: [
+    {
+      code: `
+        import { currentRouteName } from '@ember/test-helpers';
+
+        assert.equal(currentRouteName(), '/foo');
+      `,
+      output: null,
+      errors: [{ message: ERROR_MESSAGE, line: 4, column: 22 }],
+    },
+    {
+      code: `
+        import { currentRouteName as foo } from '@ember/test-helpers';
+
+        assert.equal(foo(), '/foo');
+      `,
+      output: null,
+      errors: [{ message: ERROR_MESSAGE, line: 4, column: 22 }],
+    },
+  ],
+});
diff --git a/tests/lib/rules/require-fetch-import.js b/tests/lib/rules/require-fetch-import.js
deleted file mode 100644
index 7fbd21b4..00000000
--- a/tests/lib/rules/require-fetch-import.js
+++ /dev/null
@@ -1,40 +0,0 @@
-'use strict';
-
-const rule = require('../../../lib/rules/require-fetch-import');
-const RuleTester = require('eslint').RuleTester;
-
-const { ERROR_MESSAGE } = rule;
-
-const ruleTester = new RuleTester({
-  parserOptions: { ecmaVersion: 6, sourceType: 'module' },
-  env: { browser: true },
-});
-
-ruleTester.run('require-fetch-import', rule, {
-  valid: [
-    `
-      import fetch from 'fetch';
-
-      fetch('/something');
-    `,
-    `
-      fetch('/something');
-
-      import fetch from 'fetch';
-    `,
-    `
-      import { default as fetch } from 'fetch';
-
-      fetch('/something');
-    `,
-    "foo('/something');",
-  ],
-
-  invalid: [
-    {
-      code: "fetch('/something');",
-      output: null,
-      errors: [{ message: ERROR_MESSAGE, type: 'CallExpression', line: 1, column: 1 }],
-    },
-  ],
-});