Repository: avajs/eslint-plugin-ava
Pull request #330 (2021-07-10 14:22:39)

Fixes and updates in anticipation of AVA 4
I think we can ship this as a major version, it should work equally well with AVA 3 though it does remove `test.cb()` support which of course still works in AVA 3.

- Simplify `use-t` to only check the first parameter
- Fix `no-identical-title` when there is no title
- Support `test.macro()`
- Remove callback-test related rules
- Support `test.default`



Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d23c299..790aa71 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -13,7 +13,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        node-version: [^10.18.0, ^12.14.0, ^14]
+        node-version: [^12.22, ^14.17, ^16.4]
     steps:
       - uses: actions/checkout@v1
         with:
@@ -25,16 +25,17 @@ jobs:
       - run: npm test
       - uses: codecov/codecov-action@v1
 
-  integration:
-    name: Integration tests
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v1
-        with:
-          fetch-depth: 1
-      - uses: actions/setup-node@v1
-        with:
-          node-version: ^14
-      - run: npm install --no-audit
-      - run: npm run integration
-      - uses: codecov/codecov-action@v1
+  # FIXME: https://github.com/avajs/eslint-plugin-ava/issues/333
+  # integration:
+  #   name: Integration tests
+  #   runs-on: ubuntu-latest
+  #   steps:
+  #     - uses: actions/checkout@v1
+  #       with:
+  #         fetch-depth: 1
+  #     - uses: actions/setup-node@v1
+  #       with:
+  #         node-version: ^14
+  #     - run: npm install --no-audit
+  #     - run: npm run integration
+  #     - uses: codecov/codecov-action@v1
diff --git a/create-ava-rule.js b/create-ava-rule.js
index ac1b189..f6d3a6a 100644
--- a/create-ava-rule.js
+++ b/create-ava-rule.js
@@ -1,7 +1,6 @@
-'use strict';
+const {isDeepStrictEqual} = require('util');
 const espurify = require('espurify');
 const enhance = require('enhance-visitors');
-const deepStrictEqual = require('deep-strict-equal');
 const util = require('./util');
 
 const avaImportDeclarationAsts = [{
@@ -11,14 +10,14 @@ const avaImportDeclarationAsts = [{
 			type: 'ImportDefaultSpecifier',
 			local: {
 				type: 'Identifier',
-				name: 'test'
-			}
-		}
+				name: 'test',
+			},
+		},
 	],
 	source: {
 		type: 'Literal',
-		value: 'ava'
-	}
+		value: 'ava',
+	},
 }, {
 	type: 'ImportDeclaration',
 	specifiers: [
@@ -26,18 +25,18 @@ const avaImportDeclarationAsts = [{
 			type: 'ImportSpecifier',
 			imported: {
 				type: 'Identifier',
-				name: 'serial'
+				name: 'serial',
 			},
 			local: {
 				type: 'Identifier',
-				name: 'test'
-			}
-		}
+				name: 'test',
+			},
+		},
 	],
 	source: {
 		type: 'Literal',
-		value: 'ava'
-	}
+		value: 'ava',
+	},
 }, {
 	type: 'ImportDeclaration',
 	specifiers: [
@@ -45,18 +44,18 @@ const avaImportDeclarationAsts = [{
 			type: 'ImportSpecifier',
 			imported: {
 				type: 'Identifier',
-				name: 'serial'
+				name: 'serial',
 			},
 			local: {
 				type: 'Identifier',
-				name: 'test'
-			}
-		}
+				name: 'test',
+			},
+		},
 	],
 	source: {
 		type: 'Literal',
-		value: 'ava'
-	}
+		value: 'ava',
+	},
 }, {
 	type: 'ImportDeclaration',
 	specifiers: [
@@ -64,39 +63,39 @@ const avaImportDeclarationAsts = [{
 			type: 'ImportSpecifier',
 			imported: {
 				type: 'Identifier',
-				name: 'serial'
+				name: 'serial',
 			},
 			local: {
 				type: 'Identifier',
-				name: 'serial'
-			}
-		}
+				name: 'serial',
+			},
+		},
 	],
 	source: {
 		type: 'Literal',
-		value: 'ava'
-	}
+		value: 'ava',
+	},
 }];
 
 const avaVariableDeclaratorAsts = [{
 	type: 'VariableDeclarator',
 	id: {
 		type: 'Identifier',
-		name: 'test'
+		name: 'test',
 	},
 	init: {
 		type: 'CallExpression',
 		callee: {
 			type: 'Identifier',
-			name: 'require'
+			name: 'require',
 		},
 		arguments: [
 			{
 				type: 'Literal',
-				value: 'ava'
-			}
-		]
-	}
+				value: 'ava',
+			},
+		],
+	},
 }, {
 	type: 'VariableDeclarator',
 	id: {
@@ -105,31 +104,31 @@ const avaVariableDeclaratorAsts = [{
 			type: 'Property',
 			key: {
 				type: 'Identifier',
-				name: 'serial'
+				name: 'serial',
 			},
 			value: {
 				type: 'Identifier',
-				name: 'serial'
+				name: 'serial',
 			},
 			kind: 'init',
 			method: false,
 			shorthand: true,
-			computed: false
-		}]
+			computed: false,
+		}],
 	},
 	init: {
 		type: 'CallExpression',
 		callee: {
 			type: 'Identifier',
-			name: 'require'
+			name: 'require',
 		},
 		arguments: [
 			{
 				type: 'Literal',
-				value: 'ava'
-			}
-		]
-	}
+				value: 'ava',
+			},
+		],
+	},
 }, {
 	type: 'VariableDeclarator',
 	id: {
@@ -138,31 +137,31 @@ const avaVariableDeclaratorAsts = [{
 			type: 'Property',
 			key: {
 				type: 'Identifier',
-				name: 'serial'
+				name: 'serial',
 			},
 			value: {
 				type: 'Identifier',
-				name: 'test'
+				name: 'test',
 			},
 			kind: 'init',
 			method: false,
 			shorthand: false,
-			computed: false
-		}]
+			computed: false,
+		}],
 	},
 	init: {
 		type: 'CallExpression',
 		callee: {
 			type: 'Identifier',
-			name: 'require'
+			name: 'require',
 		},
 		arguments: [
 			{
 				type: 'Literal',
-				value: 'ava'
-			}
-		]
-	}
+				value: 'ava',
+			},
+		],
+	},
 }];
 
 function isTestFunctionCall(node) {
@@ -188,12 +187,12 @@ module.exports = () => { // eslint-disable-line eslint-plugin/prefer-object-rule
 	/* eslint quote-props: [2, "as-needed"] */
 	const predefinedRules = {
 		ImportDeclaration: node => {
-			if (!isTestFile && avaImportDeclarationAsts.some(ast => deepStrictEqual(espurify(node), ast))) {
+			if (!isTestFile && avaImportDeclarationAsts.some(ast => isDeepStrictEqual(espurify(node), ast))) {
 				isTestFile = true;
 			}
 		},
 		VariableDeclarator: node => {
-			if (!isTestFile && avaVariableDeclaratorAsts.some(ast => deepStrictEqual(espurify(node), ast))) {
+			if (!isTestFile && avaVariableDeclaratorAsts.some(ast => isDeepStrictEqual(espurify(node), ast))) {
 				isTestFile = true;
 			}
 		},
@@ -211,21 +210,22 @@ module.exports = () => { // eslint-disable-line eslint-plugin/prefer-object-rule
 		},
 		'Program:exit': () => {
 			isTestFile = false;
-		}
+		},
 	};
 
 	return {
 		hasTestModifier: mod => getTestModifierNames(currentTestNode).includes(mod),
-		hasNoHookModifier: () => {
+		hasNoUtilityModifier: () => {
 			const modifiers = getTestModifierNames(currentTestNode);
-			return !modifiers.includes('before') &&
-				!modifiers.includes('beforeEach') &&
-				!modifiers.includes('after') &&
-				!modifiers.includes('afterEach');
+			return !modifiers.includes('before')
+				&& !modifiers.includes('beforeEach')
+				&& !modifiers.includes('after')
+				&& !modifiers.includes('afterEach')
+				&& !modifiers.includes('macro');
 		},
 		isInTestFile: () => isTestFile,
 		isInTestNode: () => currentTestNode,
 		isTestNode: node => currentTestNode === node,
-		merge: customHandlers => enhance.mergeVisitors([predefinedRules, customHandlers])
+		merge: customHandlers => enhance.mergeVisitors([predefinedRules, customHandlers]),
 	};
 };
diff --git a/docs/rules/no-duplicate-modifiers.md b/docs/rules/no-duplicate-modifiers.md
index e4bd251..10b6be3 100644
--- a/docs/rules/no-duplicate-modifiers.md
+++ b/docs/rules/no-duplicate-modifiers.md
@@ -11,9 +11,7 @@ const test = require('ava');
 
 test.only.only(t => {});
 test.serial.serial(t => {});
-test.cb.cb(t => {});
 test.beforeEach.beforeEach(t => {});
-test.only.only.cb(t => {});
 ```
 
 ## Pass
@@ -23,6 +21,5 @@ const test = require('ava');
 
 test.only(t => {});
 test.serial(t => {});
-test.cb.only(t => {});
 test.beforeEach(t => {});
 ```
diff --git a/docs/rules/no-invalid-end.md b/docs/rules/no-invalid-end.md
deleted file mode 100644
index f1eb29a..0000000
--- a/docs/rules/no-invalid-end.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Ensure `t.end()` is only called inside `test.cb()`
-
-Translations: [Français](https://github.com/avajs/ava-docs/blob/main/fr_FR/related/eslint-plugin-ava/docs/rules/no-invalid-end.md)
-
-AVA will fail if `t.end()` is called in a non-`.cb` test function.
-
-## Fail
-
-```js
-const test = require('ava');
-
-test('some test', t => {
-	t.pass();
-	t.end();
-});
-```
-
-## Pass
-
-```js
-const test = require('ava');
-
-test('some test', t => {
-	t.pass();
-});
-
-test.cb('some test', t => {
-	t.pass();
-	t.end();
-});
-```
diff --git a/docs/rules/no-statement-after-end.md b/docs/rules/no-statement-after-end.md
deleted file mode 100644
index 3583e14..0000000
--- a/docs/rules/no-statement-after-end.md
+++ /dev/null
@@ -1,47 +0,0 @@
-# Ensure `t.end()` is the last statement executed.
-
-Translations: [Français](https://github.com/avajs/ava-docs/blob/main/fr_FR/related/eslint-plugin-ava/docs/rules/no-statement-after-end.md)
-
-`t.end()` should mark the end of your test, and additional statements should not be executed.
-
-## Fail
-
-```js
-const test = require('ava');
-
-test.cb(t => {
-	t.end();
-	t.is(1, 1);
-});
-
-test.cb(t => {
-	t.end();
-	console.log('at the end');
-});
-```
-
-## Pass
-
-```js
-const test = require('ava');
-
-test.cb(t => {
-	t.is(1, 1);
-	t.end();
-});
-const test = require('ava');
-
-test.cb(t => {
-	if (a) {
-		// Allowed because no further statements are reachable.
-		return t.end();
-	}
-	if (b) {
-		t.end();
-		return;
-	}
-	t.is(1, 1);
-	t.end();
-});
-
-```
diff --git a/docs/rules/no-unknown-modifiers.md b/docs/rules/no-unknown-modifiers.md
index c4a5f7e..d5f236f 100644
--- a/docs/rules/no-unknown-modifiers.md
+++ b/docs/rules/no-unknown-modifiers.md
@@ -11,7 +11,6 @@ const test = require('ava');
 
 test.onlu(t => {});
 test.seril(t => {});
-test.cb.onlu(t => {});
 test.beforeeach(t => {});
 test.unknown(t => {});
 ```
@@ -23,6 +22,5 @@ const test = require('ava');
 
 test.only(t => {});
 test.serial(t => {});
-test.cb.only(t => {});
 test.beforeEach(t => {});
 ```
diff --git a/docs/rules/use-t.md b/docs/rules/use-t.md
index 22d4ddf..ee4160d 100644
--- a/docs/rules/use-t.md
+++ b/docs/rules/use-t.md
@@ -12,14 +12,6 @@ const test = require('ava');
 test('foo', foo => { // Incorrect name
 	t.pass();
 });
-
-test('bar', (t, bar) => { // too many arguments
-	t.pass();
-});
-
-test('baz', (bar, t) => { // too many arguments
-	t.pass();
-});
 ```
 
 ### Pass
diff --git a/index.js b/index.js
index 5559539..269de8f 100644
--- a/index.js
+++ b/index.js
@@ -1,4 +1,3 @@
-'use strict';
 const path = require('path');
 const importModules = require('import-modules');
 
@@ -7,51 +6,47 @@ module.exports = {
 	configs: {
 		recommended: {
 			env: {
-				es6: true
+				es6: true,
 			},
 			parserOptions: {
 				ecmaVersion: 2021,
-				sourceType: 'module'
+				sourceType: 'module',
 			},
 			plugins: [
-				'ava'
+				'ava',
 			],
 			rules: {
 				'ava/assertion-arguments': 'error',
 				'ava/hooks-order': 'error',
 				'ava/max-asserts': [
 					'off',
-					5
+					5,
 				],
 				'ava/no-async-fn-without-await': 'error',
-				'ava/no-cb-test': 'off',
 				'ava/no-duplicate-modifiers': 'error',
 				'ava/no-identical-title': 'error',
 				'ava/no-ignored-test-files': 'error',
 				'ava/no-import-test-files': 'error',
 				'ava/no-incorrect-deep-equal': 'error',
 				'ava/no-inline-assertions': 'error',
-				'ava/no-invalid-end': 'error',
 				'ava/no-nested-tests': 'error',
 				'ava/no-only-test': 'error',
 				'ava/no-skip-assert': 'error',
 				'ava/no-skip-test': 'error',
-				'ava/no-statement-after-end': 'error',
 				'ava/no-todo-implementation': 'error',
 				'ava/no-todo-test': 'warn',
 				'ava/no-unknown-modifiers': 'error',
 				'ava/prefer-async-await': 'error',
 				'ava/prefer-power-assert': 'off',
 				'ava/prefer-t-regex': 'error',
-				'ava/test-ended': 'error',
 				'ava/test-title': 'error',
 				'ava/test-title-format': 'off',
 				'ava/use-t-well': 'error',
 				'ava/use-t': 'error',
 				'ava/use-t-throws-async-well': 'error',
 				'ava/use-test': 'error',
-				'ava/use-true-false': 'error'
-			}
-		}
-	}
+				'ava/use-true-false': 'error',
+			},
+		},
+	},
 };
diff --git a/package.json b/package.json
index 06811d9..aedd004 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
 	"license": "MIT",
 	"repository": "avajs/eslint-plugin-ava",
 	"engines": {
-		"node": ">=10.18.0 <11 || >=12.14.0 <13 || >=14"
+		"node": ">=12.22 <13 || >=14.17 <15 || >=16.4"
 	},
 	"scripts": {
 		"test": "xo && c8 ava",
@@ -30,11 +30,10 @@
 		"mocha"
 	],
 	"dependencies": {
-		"deep-strict-equal": "^0.2.0",
 		"enhance-visitors": "^1.0.0",
-		"eslint-utils": "^2.1.0",
-		"espree": "^7.3.1",
-		"espurify": "^2.0.1",
+		"eslint-utils": "^3.0.0",
+		"espree": "^9.0.0",
+		"espurify": "^2.1.1",
 		"import-modules": "^2.1.0",
 		"micro-spelling-correcter": "^1.1.1",
 		"pkg-dir": "^5.0.0",
@@ -42,19 +41,18 @@
 	},
 	"devDependencies": {
 		"ava": "^3.15.0",
-		"babel-eslint": "^10.1.0",
-		"c8": "^7.6.0",
-		"chalk": "^4.1.0",
+		"c8": "^7.7.3",
+		"chalk": "^4.1.1",
 		"del": "^6.0.0",
-		"eslint": "^7.8.1",
+		"eslint": "^7.32.0",
 		"eslint-ava-rule-tester": "^4.0.0",
-		"eslint-plugin-eslint-plugin": "^2.3.0",
-		"execa": "^5.0.0",
+		"eslint-plugin-eslint-plugin": "^3.5.3",
+		"execa": "^5.1.1",
 		"listr": "^0.14.3",
 		"outdent": "^0.8.0",
 		"pify": "^5.0.0",
 		"tempy": "^1.0.1",
-		"xo": "^0.38.2"
+		"xo": "^0.44.0"
 	},
 	"peerDependencies": {
 		"eslint": ">=7.22.0"
@@ -81,7 +79,11 @@
 			}
 		],
 		"rules": {
-			"ava/no-ignored-test-files": "off"
+			"ava/no-ignored-test-files": "off",
+			"eslint-plugin/prefer-message-ids": "off",
+			"eslint-plugin/require-meta-docs-description": "off",
+			"import/extensions": "off",
+			"unicorn/prefer-module": "off"
 		}
 	},
 	"c8": {
diff --git a/readme.md b/readme.md
index cc80a4e..70f5414 100644
--- a/readme.md
+++ b/readme.md
@@ -40,26 +40,22 @@ Configure it in `package.json`.
 				5
 			],
 			"ava/no-async-fn-without-await": "error",
-			"ava/no-cb-test": "off",
 			"ava/no-duplicate-modifiers": "error",
 			"ava/no-identical-title": "error",
 			"ava/no-ignored-test-files": "error",
 			"ava/no-import-test-files": "error",
 			"ava/no-incorrect-deep-equal": "error",
 			"ava/no-inline-assertions": "error",
-			"ava/no-invalid-end": "error",
 			"ava/no-nested-tests": "error",
 			"ava/no-only-test": "error",
 			"ava/no-skip-assert": "error",
 			"ava/no-skip-test": "error",
-			"ava/no-statement-after-end": "error",
 			"ava/no-todo-implementation": "error",
 			"ava/no-todo-test": "warn",
 			"ava/no-unknown-modifiers": "error",
 			"ava/prefer-async-await": "error",
 			"ava/prefer-power-assert": "off",
 			"ava/prefer-t-regex": "error",
-			"ava/test-ended": "error",
 			"ava/test-title": "error",
 			"ava/test-title-format": "off",
 			"ava/use-t": "error",
@@ -80,26 +76,22 @@ The rules will only activate in test files.
 - [hooks-order](docs/rules/hooks-order.md) - Enforce test hook ordering. *(fixable)*
 - [max-asserts](docs/rules/max-asserts.md) - Limit the number of assertions in a test.
 - [no-async-fn-without-await](docs/rules/no-async-fn-without-await.md) - Ensure that async tests use `await`.
-- [no-cb-test](docs/rules/no-cb-test.md) - Ensure no `test.cb()` is used.
 - [no-duplicate-modifiers](docs/rules/no-duplicate-modifiers.md) - Ensure tests do not have duplicate modifiers.
 - [no-identical-title](docs/rules/no-identical-title.md) - Ensure no tests have the same title.
 - [no-ignored-test-files](docs/rules/no-ignored-test-files.md) - Ensure no tests are written in ignored files.
 - [no-import-test-files](docs/rules/no-import-test-files.md) - Ensure no test files are imported anywhere.
 - [no-incorrect-deep-equal](docs/rules/no-incorrect-deep-equal.md) - Avoid using `deepEqual` with primitives. *(fixable)*
 - [no-inline-assertions](docs/rules/no-inline-assertions.md) - Ensure assertions are not called from inline arrow functions. *(fixable)*
-- [no-invalid-end](docs/rules/no-invalid-end.md) - Ensure `t.end()` is only called inside `test.cb()`.
 - [no-nested-tests](docs/rules/no-nested-tests.md) - Ensure no tests are nested.
 - [no-only-test](docs/rules/no-only-test.md) - Ensure no `test.only()` are present.
 - [no-skip-assert](docs/rules/no-skip-assert.md) - Ensure no assertions are skipped.
 - [no-skip-test](docs/rules/no-skip-test.md) - Ensure no tests are skipped.
-- [no-statement-after-end](docs/rules/no-statement-after-end.md) - Ensure `t.end()` is the last statement executed.
 - [no-todo-implementation](docs/rules/no-todo-implementation.md) - Ensure `test.todo()` is not given an implementation function.
 - [no-todo-test](docs/rules/no-todo-test.md) - Ensure no `test.todo()` is used.
 - [no-unknown-modifiers](docs/rules/no-unknown-modifiers.md) - Prevent the use of unknown test modifiers.
 - [prefer-async-await](docs/rules/prefer-async-await.md) - Prefer using async/await instead of returning a Promise.
 - [prefer-power-assert](docs/rules/prefer-power-assert.md) - Allow only use of the asserts that have no [power-assert](https://github.com/power-assert-js/power-assert) alternative.
 - [prefer-t-regex](docs/rules/prefer-t-regex.md) - Prefer using `t.regex()` to test regular expressions. *(fixable)*
-- [test-ended](docs/rules/test-ended.md) - Ensure callback tests are explicitly ended.
 - [test-title](docs/rules/test-title.md) - Ensure tests have a title.
 - [test-title-format](docs/rules/test-title-format.md) - Ensure test titles have a certain format.
 - [use-t](docs/rules/use-t.md) - Ensure test functions use `t` as their parameter.
diff --git a/rules/assertion-arguments.js b/rules/assertion-arguments.js
index 0f6bbaa..7054b94 100644
--- a/rules/assertion-arguments.js
+++ b/rules/assertion-arguments.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const {getStaticValue, isOpeningParenToken, isCommaToken, findVariable} = require('eslint-utils');
 const util = require('../util');
@@ -7,96 +6,96 @@ const createAvaRule = require('../create-ava-rule');
 const expectedNbArguments = {
 	assert: {
 		min: 1,
-		max: 2
+		max: 2,
 	},
 	deepEqual: {
 		min: 2,
-		max: 3
+		max: 3,
 	},
 	fail: {
 		min: 0,
-		max: 1
+		max: 1,
 	},
 	false: {
 		min: 1,
-		max: 2
+		max: 2,
 	},
 	falsy: {
 		min: 1,
-		max: 2
+		max: 2,
 	},
 	ifError: {
 		min: 1,
-		max: 2
+		max: 2,
 	},
 	is: {
 		min: 2,
-		max: 3
+		max: 3,
 	},
 	like: {
 		min: 2,
-		max: 3
+		max: 3,
 	},
 	not: {
 		min: 2,
-		max: 3
+		max: 3,
 	},
 	notDeepEqual: {
 		min: 2,
-		max: 3
+		max: 3,
 	},
 	notThrows: {
 		min: 1,
-		max: 2
+		max: 2,
 	},
 	notThrowsAsync: {
 		min: 1,
-		max: 2
+		max: 2,
 	},
 	pass: {
 		min: 0,
-		max: 1
+		max: 1,
 	},
 	plan: {
 		min: 1,
-		max: 1
+		max: 1,
 	},
 	regex: {
 		min: 2,
-		max: 3
+		max: 3,
 	},
 	notRegex: {
 		min: 2,
-		max: 3
+		max: 3,
 	},
 	snapshot: {
 		min: 1,
-		max: 2
+		max: 2,
 	},
 	teardown: {
 		min: 1,
-		max: 1
+		max: 1,
 	},
 	throws: {
 		min: 1,
-		max: 3
+		max: 3,
 	},
 	throwsAsync: {
 		min: 1,
-		max: 3
+		max: 3,
 	},
 	true: {
 		min: 1,
-		max: 2
+		max: 2,
 	},
 	truthy: {
 		min: 1,
-		max: 2
+		max: 2,
 	},
 	timeout: {
 		min: 1,
-		max: 2
-	}
+		max: 2,
+	},
 };
 
 const actualExpectedAssertions = new Set([
@@ -106,7 +105,7 @@ const actualExpectedAssertions = new Set([
 	'not',
 	'notDeepEqual',
 	'throws',
-	'throwsAsync'
+	'throwsAsync',
 ]);
 
 const relationalActualExpectedAssertions = new Set([
@@ -114,7 +113,7 @@ const relationalActualExpectedAssertions = new Set([
 	'truthy',
 	'falsy',
 	'true',
-	'false'
+	'false',
 ]);
 
 const comparisonOperators = new Map([
@@ -125,7 +124,7 @@ const comparisonOperators = new Map([
 	['!=', '!='],
 	['!==', '!=='],
 	['<=', '>='],
-	['<', '>']
+	['<', '>'],
 ]);
 
 const flipOperator = operator => comparisonOperators.get(operator);
@@ -138,34 +137,34 @@ function isStatic(node) {
 function * sourceRangesOfArguments(sourceCode, callExpression) {
 	const openingParen = sourceCode.getTokenAfter(
 		callExpression.callee,
-		{filter: token => isOpeningParenToken(token)}
+		{filter: token => isOpeningParenToken(token)},
 	);
 
 	const closingParen = sourceCode.getLastToken(callExpression);
 
 	for (const [index, argument] of callExpression.arguments.entries()) {
-		const previousToken = index === 0 ?
-			openingParen :
-			sourceCode.getTokenBefore(
+		const previousToken = index === 0
+			? openingParen
+			: sourceCode.getTokenBefore(
 				argument,
-				{filter: token => isCommaToken(token)}
+				{filter: token => isCommaToken(token)},
 			);
 
-		const nextToken = index === callExpression.arguments.length - 1 ?
-			closingParen :
-			sourceCode.getTokenAfter(
+		const nextToken = index === callExpression.arguments.length - 1
+			? closingParen
+			: sourceCode.getTokenAfter(
 				argument,
-				{filter: token => isCommaToken(token)}
+				{filter: token => isCommaToken(token)},
 			);
 
 		const firstToken = sourceCode.getTokenAfter(
 			previousToken,
-			{includeComments: true}
+			{includeComments: true},
 		);
 
 		const lastToken = sourceCode.getTokenBefore(
 			nextToken,
-			{includeComments: true}
+			{includeComments: true},
 		);
 
 		yield [firstToken.range[0], lastToken.range[1]];
@@ -178,7 +177,7 @@ function sourceOfBinaryExpressionComponents(sourceCode, node) {
 	const operatorToken = sourceCode.getFirstTokenBetween(
 		left,
 		right,
-		{filter: token => token.value === operator}
+		{filter: token => token.value === operator},
 	);
 
 	const previousToken = sourceCode.getTokenBefore(node);
@@ -186,28 +185,26 @@ function sourceOfBinaryExpressionComponents(sourceCode, node) {
 
 	const leftRange = [
 		sourceCode.getTokenAfter(previousToken, {includeComments: true}).range[0],
-		sourceCode.getTokenBefore(operatorToken, {includeComments: true}).range[1]
+		sourceCode.getTokenBefore(operatorToken, {includeComments: true}).range[1],
 	];
 
 	const rightRange = [
 		sourceCode.getTokenAfter(operatorToken, {includeComments: true}).range[0],
-		sourceCode.getTokenBefore(nextToken, {includeComments: true}).range[1]
+		sourceCode.getTokenBefore(nextToken, {includeComments: true}).range[1],
 	];
 
 	return [leftRange, operatorToken, rightRange];
 }
 
 function noComments(sourceCode, ...nodes) {
-	return nodes.every(node => {
-		return sourceCode.getCommentsBefore(node).length === 0 && sourceCode.getCommentsAfter(node).length === 0;
-	});
+	return nodes.every(node => sourceCode.getCommentsBefore(node).length === 0 && sourceCode.getCommentsAfter(node).length === 0);
 }
 
 function isString(node) {
 	const {type} = node;
-	return type === 'TemplateLiteral' ||
-		type === 'TaggedTemplateExpression' ||
-		(type === 'Literal' && typeof node.value === 'string');
+	return type === 'TemplateLiteral'
+		|| type === 'TaggedTemplateExpression'
+		|| (type === 'Literal' && typeof node.value === 'string');
 }
 
 const create = context => {
@@ -223,15 +220,15 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isInTestNode
+			ava.isInTestNode,
 		])(node => {
 			const {callee} = node;
 
 			if (
-				callee.type !== 'MemberExpression' ||
-				!callee.property ||
-				util.getNameOfRootNodeObject(callee) !== 't' ||
-				util.isPropertyUnderContext(callee)
+				callee.type !== 'MemberExpression'
+				|| !callee.property
+				|| util.getNameOfRootNodeObject(callee) !== 't'
+				|| util.isPropertyUnderContext(callee)
 			) {
 				return;
 			}
@@ -296,7 +293,7 @@ const create = context => {
 					report(node, 'Assertion message should be a string.');
 				}
 			}
-		})
+		}),
 	});
 };
 
@@ -306,19 +303,19 @@ function checkArgumentOrder({node, assertion, context}) {
 		const [leftNode, rightNode] = [first, second];
 		if (isStatic(leftNode) && !isStatic(rightNode)) {
 			context.report(
-				makeOutOfOrder2ArgumentReport({node, leftNode, rightNode, context})
+				makeOutOfOrder2ArgumentReport({node, leftNode, rightNode, context}),
 			);
 		}
 	} else if (
-		relationalActualExpectedAssertions.has(assertion) &&
-		first &&
-		first.type === 'BinaryExpression' &&
-		comparisonOperators.has(first.operator)
+		relationalActualExpectedAssertions.has(assertion)
+		&& first
+		&& first.type === 'BinaryExpression'
+		&& comparisonOperators.has(first.operator)
 	) {
 		const [leftNode, rightNode] = [first.left, first.right];
 		if (isStatic(leftNode) && !isStatic(rightNode)) {
 			context.report(
-				makeOutOfOrder1ArgumentReport({node: first, leftNode, rightNode, context})
+				makeOutOfOrder1ArgumentReport({node: first, leftNode, rightNode, context}),
 			);
 		}
 	}
@@ -331,8 +328,8 @@ function makeOutOfOrder2ArgumentReport({node, leftNode, rightNode, context}) {
 		message: 'Expected values should come after actual values.',
 		loc: {
 			start: sourceCode.getLocFromIndex(leftRange[0]),
-			end: sourceCode.getLocFromIndex(rightRange[1])
-		}
+			end: sourceCode.getLocFromIndex(rightRange[1]),
+		},
 	};
 
 	if (noComments(sourceCode, leftNode, rightNode)) {
@@ -341,7 +338,7 @@ function makeOutOfOrder2ArgumentReport({node, leftNode, rightNode, context}) {
 			const rightText = sourceCode.getText().slice(...rightRange);
 			return [
 				fixer.replaceTextRange(leftRange, rightText),
-				fixer.replaceTextRange(rightRange, leftText)
+				fixer.replaceTextRange(rightRange, leftText),
 			];
 		};
 	}
@@ -354,14 +351,14 @@ function makeOutOfOrder1ArgumentReport({node, leftNode, rightNode, context}) {
 	const [
 		leftRange,
 		operatorToken,
-		rightRange
+		rightRange,
 	] = sourceOfBinaryExpressionComponents(sourceCode, node);
 	const report = {
 		message: 'Expected values should come after actual values.',
 		loc: {
 			start: sourceCode.getLocFromIndex(leftRange[0]),
-			end: sourceCode.getLocFromIndex(rightRange[1])
-		}
+			end: sourceCode.getLocFromIndex(rightRange[1]),
+		},
 	};
 
 	if (noComments(sourceCode, leftNode, rightNode, node)) {
@@ -371,7 +368,7 @@ function makeOutOfOrder1ArgumentReport({node, leftNode, rightNode, context}) {
 			return [
 				fixer.replaceTextRange(leftRange, rightText),
 				fixer.replaceText(operatorToken, flipOperator(node.operator)),
-				fixer.replaceTextRange(rightRange, leftText)
+				fixer.replaceTextRange(rightRange, leftText),
 			];
 		};
 	}
@@ -385,21 +382,21 @@ const schema = [{
 		message: {
 			enum: [
 				'always',
-				'never'
+				'never',
 			],
-			default: undefined
-		}
-	}
+			default: undefined,
+		},
+	},
 }];
 
 module.exports = {
 	create,
 	meta: {
-		fixable: 'code',
+		type: 'problem',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
+		fixable: 'code',
 		schema,
-		type: 'problem'
-	}
+	},
 };
diff --git a/rules/hooks-order.js b/rules/hooks-order.js
index e4f847c..4e4cae9 100644
--- a/rules/hooks-order.js
+++ b/rules/hooks-order.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const createAvaRule = require('../create-ava-rule');
 const util = require('../util');
@@ -30,9 +29,9 @@ const buildMessage = (name, orders, visited) => {
 				messageId: MESSAGE_ID,
 				data: {
 					current: name,
-					invalid: check
+					invalid: check,
 				},
-				node: nodeEarlier
+				node: nodeEarlier,
 			};
 		}
 	}
@@ -50,7 +49,7 @@ const create = context => {
 		'beforeEach',
 		'afterEach',
 		'afterEach.always',
-		'test'
+		'test',
 	]);
 
 	const visited = {};
@@ -58,42 +57,42 @@ const create = context => {
 	const checks = [
 		{
 			selector: 'CallExpression[callee.object.name="test"][callee.property.name="before"]',
-			name: 'before'
+			name: 'before',
 		},
 		{
 			selector: 'CallExpression[callee.object.name="test"][callee.property.name="after"]',
-			name: 'after'
+			name: 'after',
 		},
 		{
 			selector: 'CallExpression[callee.object.object.name="test"][callee.object.property.name="after"][callee.property.name="always"]',
-			name: 'after.always'
+			name: 'after.always',
 		},
 		{
 			selector: 'CallExpression[callee.object.name="test"][callee.property.name="beforeEach"]',
-			name: 'beforeEach'
+			name: 'beforeEach',
 		},
 		{
 			selector: 'CallExpression[callee.object.name="test"][callee.property.name="afterEach"]',
-			name: 'afterEach'
+			name: 'afterEach',
 		},
 		{
 			selector: 'CallExpression[callee.object.object.name="test"][callee.object.property.name="afterEach"][callee.property.name="always"]',
-			name: 'afterEach.always'
+			name: 'afterEach.always',
 		},
 		{
 			selector: 'CallExpression[callee.name="test"]',
-			name: 'test'
-		}
+			name: 'test',
+		},
 	];
 
 	const sourceCode = context.getSourceCode();
 
 	// TODO: Remove `.reduce()` usage.
-	// eslint-disable-next-line unicorn/no-array-reduce
+	// eslint-disable-next-line unicorn/no-array-reduce, unicorn/prefer-object-from-entries
 	const selectors = checks.reduce((result, check) => {
 		result[check.selector] = visitIf([
 			ava.isInTestFile,
-			ava.isTestNode
+			ava.isTestNode,
 		])(node => {
 			visited[check.name] = node;
 
@@ -133,9 +132,9 @@ const create = context => {
 
 						return [
 							fixer.insertTextBeforeRange([insertStart, insertEnd], text),
-							fixer.removeRange([start, end])
+							fixer.removeRange([start, end]),
 						];
-					}
+					},
 				});
 			}
 		});
@@ -148,13 +147,14 @@ const create = context => {
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
+		fixable: 'code',
+		schema: [],
 		messages: {
-			[MESSAGE_ID]: '`{{current}}` hook must come before `{{invalid}}`'
+			[MESSAGE_ID]: '`{{current}}` hook must come before `{{invalid}}`',
 		},
-		type: 'suggestion',
-		fixable: 'code'
-	}
+	},
 };
diff --git a/rules/max-asserts.js b/rules/max-asserts.js
index fb0d75f..46b44be 100644
--- a/rules/max-asserts.js
+++ b/rules/max-asserts.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const util = require('../util');
 const createAvaRule = require('../create-ava-rule');
@@ -18,7 +17,7 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isInTestNode
+			ava.isInTestNode,
 		])(node => {
 			const {callee} = node;
 
@@ -27,9 +26,9 @@ const create = context => {
 			}
 
 			if (
-				callee.property &&
-				!notAssertionMethods.has(callee.property.name) &&
-				util.getNameOfRootNodeObject(callee) === 't'
+				callee.property
+				&& !notAssertionMethods.has(callee.property.name)
+				&& util.getNameOfRootNodeObject(callee) === 't'
 			) {
 				const firstNonSkipMember = util.getMembers(callee).find(name => name !== 'skip');
 
@@ -49,30 +48,30 @@ const create = context => {
 			if (assertionCount > maxAssertions) {
 				context.report({
 					node: nodeToReport,
-					message: `Expected at most ${maxAssertions} assertions, but found ${assertionCount}.`
+					message: `Expected at most ${maxAssertions} assertions, but found ${assertionCount}.`,
 				});
 			}
 
 			assertionCount = 0;
 			nodeToReport = undefined;
-		})
+		}),
 	});
 };
 
 const schema = [
 	{
 		type: 'integer',
-		default: MAX_ASSERTIONS_DEFAULT
-	}
+		default: MAX_ASSERTIONS_DEFAULT,
+	},
 ];
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
 		schema,
-		type: 'suggestion'
-	}
+	},
 };
diff --git a/rules/no-async-fn-without-await.js b/rules/no-async-fn-without-await.js
index 22b7bb8..29b0c24 100644
--- a/rules/no-async-fn-without-await.js
+++ b/rules/no-async-fn-without-await.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const createAvaRule = require('../create-ava-rule');
 const util = require('../util');
@@ -19,41 +18,42 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isTestNode
+			ava.isTestNode,
 		])(node => {
-			asyncTest = (isAsync(node.arguments[0]) && node.arguments[0]) ||
-				(isAsync(node.arguments[1]) && node.arguments[1]);
+			asyncTest = (isAsync(node.arguments[0]) && node.arguments[0])
+				|| (isAsync(node.arguments[1]) && node.arguments[1]);
 		}),
 		AwaitExpression: registerUseOfAwait,
 		YieldExpression: registerUseOfAwait,
 		'ForOfStatement[await=true]': registerUseOfAwait,
 		'CallExpression:exit': visitIf([
 			ava.isInTestFile,
-			ava.isTestNode
+			ava.isTestNode,
 		])(() => {
 			if (asyncTest && !testUsed) {
 				context.report({
 					node: asyncTest,
 					loc: {
 						start: asyncTest.loc.start,
-						end: asyncTest.loc.start + 5
+						end: asyncTest.loc.start + 5,
 					},
-					message: 'Function was declared as `async` but doesn\'t use `await`.'
+					message: 'Function was declared as `async` but doesn\'t use `await`.',
 				});
 			}
 
 			asyncTest = undefined;
 			testUsed = false;
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		type: 'suggestion'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/no-duplicate-modifiers.js b/rules/no-duplicate-modifiers.js
index 2040f81..bd0f28e 100644
--- a/rules/no-duplicate-modifiers.js
+++ b/rules/no-duplicate-modifiers.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const util = require('../util');
 const createAvaRule = require('../create-ava-rule');
@@ -21,7 +20,7 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isTestNode
+			ava.isTestNode,
 		])(node => {
 			const testModifiers = util.getTestModifiers(node).sort(sortByName);
 
@@ -35,22 +34,23 @@ const create = context => {
 				if (previous.name === current.name) {
 					context.report({
 						node: current,
-						message: `Duplicate test modifier \`.${current.name}\`.`
+						message: `Duplicate test modifier \`.${current.name}\`.`,
 					});
 				}
 
 				return current;
 			});
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'problem',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		type: 'problem'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/no-identical-title.js b/rules/no-identical-title.js
index 96d4e71..82acb6c 100644
--- a/rules/no-identical-title.js
+++ b/rules/no-identical-title.js
@@ -1,7 +1,6 @@
-'use strict';
+const {isDeepStrictEqual} = require('util');
 const espurify = require('espurify');
 const {visitIf} = require('enhance-visitors');
-const deepStrictEqual = require('deep-strict-equal');
 const util = require('../util');
 const createAvaRule = require('../create-ava-rule');
 
@@ -9,13 +8,13 @@ const purify = node => node && espurify(node);
 
 const isStaticTemplateLiteral = node => node.expressions.every(expression => isStatic(expression));
 
-const isStatic = node => node.type === 'Literal' ||
-	(node.type === 'TemplateLiteral' && isStaticTemplateLiteral(node)) ||
-	(node.type === 'BinaryExpression' && isStatic(node.left) && isStatic(node.right));
+const isStatic = node => node.type === 'Literal'
+	|| (node.type === 'TemplateLiteral' && isStaticTemplateLiteral(node))
+	|| (node.type === 'BinaryExpression' && isStatic(node.left) && isStatic(node.right));
 
 function isTitleUsed(usedTitleNodes, titleNode) {
 	const purifiedNode = purify(titleNode);
-	return usedTitleNodes.some(usedTitle => deepStrictEqual(purifiedNode, usedTitle));
+	return usedTitleNodes.some(usedTitle => isDeepStrictEqual(purifiedNode, usedTitle));
 }
 
 const create = context => {
@@ -26,13 +25,13 @@ const create = context => {
 		CallExpression: visitIf([
 			ava.isInTestFile,
 			ava.isTestNode,
-			ava.hasNoHookModifier
+			ava.hasNoUtilityModifier,
 		])(node => {
 			const args = node.arguments;
 			const titleNode = args.length > 1 || ava.hasTestModifier('todo') ? args[0] : undefined;
 
 			// Don't flag computed titles
-			if (!isStatic(titleNode)) {
+			if (!titleNode || !isStatic(titleNode)) {
 				return;
 			}
 
@@ -44,7 +43,7 @@ const create = context => {
 			if (isTitleUsed(usedTitleNodes, titleNode)) {
 				context.report({
 					node: titleNode,
-					message: 'Test title is used multiple times in the same file.'
+					message: 'Test title is used multiple times in the same file.',
 				});
 				return;
 			}
@@ -53,16 +52,17 @@ const create = context => {
 		}),
 		'Program:exit': () => {
 			usedTitleNodes = [];
-		}
+		},
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'problem',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		type: 'problem'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/no-incorrect-deep-equal.js b/rules/no-incorrect-deep-equal.js
index 4438a6e..6106b40 100644
--- a/rules/no-incorrect-deep-equal.js
+++ b/rules/no-incorrect-deep-equal.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const util = require('../util');
 const createAvaRule = require('../create-ava-rule');
@@ -10,9 +9,9 @@ const buildDeepEqualMessage = (context, node) => {
 		node,
 		messageId: MESSAGE_ID,
 		data: {
-			callee: node.callee.property.name
+			callee: node.callee.property.name,
 		},
-		fix: fixer => fixer.replaceText(node.callee.property, 'is')
+		fix: fixer => fixer.replaceText(node.callee.property, 'is'),
 	});
 };
 
@@ -21,9 +20,9 @@ const buildNotDeepEqualMessage = (context, node) => {
 		node,
 		messageId: MESSAGE_ID,
 		data: {
-			callee: node.callee.property.name
+			callee: node.callee.property.name,
 		},
-		fix: fixer => fixer.replaceText(node.callee.property, 'not')
+		fix: fixer => fixer.replaceText(node.callee.property, 'not'),
 	});
 };
 
@@ -41,53 +40,54 @@ const create = context => {
 	return ava.merge({
 		[`${callExpression}${deepEqual}${argumentsLiteral}`]: visitIf([
 			ava.isInTestFile,
-			ava.isInTestNode
+			ava.isInTestNode,
 		])(node => {
 			buildDeepEqualMessage(context, node);
 		}),
 		[`${callExpression}${deepEqual}${argumentsUndefined}`]: visitIf([
 			ava.isInTestFile,
-			ava.isInTestNode
+			ava.isInTestNode,
 		])(node => {
 			buildDeepEqualMessage(context, node);
 		}),
 		[`${callExpression}${deepEqual}${argumentsTemplate}`]: visitIf([
 			ava.isInTestFile,
-			ava.isInTestNode
+			ava.isInTestNode,
 		])(node => {
 			buildDeepEqualMessage(context, node);
 		}),
 		[`${callExpression}${notDeepEqual}${argumentsLiteral}`]: visitIf([
 			ava.isInTestFile,
-			ava.isInTestNode
+			ava.isInTestNode,
 		])(node => {
 			buildNotDeepEqualMessage(context, node);
 		}),
 		[`${callExpression}${notDeepEqual}${argumentsUndefined}`]: visitIf([
 			ava.isInTestFile,
-			ava.isInTestNode
+			ava.isInTestNode,
 		])(node => {
 			buildNotDeepEqualMessage(context, node);
 		}),
 		[`${callExpression}${notDeepEqual}${argumentsTemplate}`]: visitIf([
 			ava.isInTestFile,
-			ava.isInTestNode
+			ava.isInTestNode,
 		])(node => {
 			buildNotDeepEqualMessage(context, node);
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		fixable: true,
+		fixable: 'code',
+		schema: [],
 		messages: {
-			[MESSAGE_ID]: 'Avoid using `{{callee}}` with literal primitives'
+			[MESSAGE_ID]: 'Avoid using `{{callee}}` with literal primitives',
 		},
-		type: 'suggestion'
-	}
+	},
 };
diff --git a/rules/no-inline-assertions.js b/rules/no-inline-assertions.js
index d1b313b..e16291f 100644
--- a/rules/no-inline-assertions.js
+++ b/rules/no-inline-assertions.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const createAvaRule = require('../create-ava-rule');
 const util = require('../util');
@@ -9,7 +8,7 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isTestNode
+			ava.isTestNode,
 		])(node => {
 			const functionArgIndex = node.arguments.length - 1;
 			if (functionArgIndex > 1) {
@@ -27,20 +26,21 @@ const create = context => {
 				context.report({
 					node,
 					message: 'The test implementation should not be an inline arrow function.',
-					fix: fixer => [fixer.insertTextBefore(body, '{'), fixer.insertTextAfter(body, '}')]
+					fix: fixer => [fixer.insertTextBefore(body, '{'), fixer.insertTextAfter(body, '}')],
 				});
 			}
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		type: 'suggestion',
-		fixable: 'code'
-	}
+		fixable: 'code',
+		schema: [],
+	},
 };
diff --git a/rules/no-invalid-end.js b/rules/no-invalid-end.js
deleted file mode 100644
index af26db5..0000000
--- a/rules/no-invalid-end.js
+++ /dev/null
@@ -1,36 +0,0 @@
-'use strict';
-const {visitIf} = require('enhance-visitors');
-const util = require('../util');
-const createAvaRule = require('../create-ava-rule');
-
-const create = context => {
-	const ava = createAvaRule();
-
-	return ava.merge({
-		MemberExpression: visitIf([
-			ava.isInTestFile,
-			ava.isInTestNode
-		])(node => {
-			if (
-				node.property.name === 'end' &&
-				node.object.name === 't' &&
-				!ava.hasTestModifier('cb')
-			) {
-				context.report({
-					node,
-					message: '`t.end()` should only be used inside of `test.cb()`.'
-				});
-			}
-		})
-	});
-};
-
-module.exports = {
-	create,
-	meta: {
-		docs: {
-			url: util.getDocsUrl(__filename)
-		},
-		type: 'problem'
-	}
-};
diff --git a/rules/no-skip-assert.js b/rules/no-skip-assert.js
index 74da2e5..a90ff3c 100644
--- a/rules/no-skip-assert.js
+++ b/rules/no-skip-assert.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const util = require('../util');
 const createAvaRule = require('../create-ava-rule');
@@ -9,27 +8,28 @@ const create = context => {
 	return ava.merge({
 		MemberExpression: visitIf([
 			ava.isInTestFile,
-			ava.isInTestNode
+			ava.isInTestNode,
 		])(node => {
 			if (node.property.name === 'skip') {
 				const root = util.getRootNode(node);
 				if (root.object.name === 't' && util.assertionMethods.has(root.property.name)) {
 					context.report({
 						node,
-						message: 'No assertions should be skipped.'
+						message: 'No assertions should be skipped.',
 					});
 				}
 			}
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		type: 'suggestion'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/no-statement-after-end.js b/rules/no-statement-after-end.js
deleted file mode 100644
index 667d9da..0000000
--- a/rules/no-statement-after-end.js
+++ /dev/null
@@ -1,117 +0,0 @@
-'use strict';
-const createAvaRule = require('../create-ava-rule');
-const util = require('../util');
-
-// This rule makes heavy use of ESLint's code path analysis
-// See: https://eslint.org/docs/developer-guide/code-path-analysis.html
-
-// Returns true if this node represents a call to `t.end(...)`
-const isEndExpression = node =>
-	node.type === 'CallExpression' &&
-	node.callee.type === 'MemberExpression' &&
-	node.callee.object.type === 'Identifier' &&
-	node.callee.object.name === 't' &&
-	node.callee.property.type === 'Identifier' &&
-	node.callee.property.name === 'end';
-
-const create = context => {
-	const ava = createAvaRule();
-	const segmentInfoMap = new Map();
-	const segmentInfoStack = [];
-
-	let currentSegmentInfo;
-
-	function pathStart() {
-		if (currentSegmentInfo !== undefined) {
-			segmentInfoStack.push(currentSegmentInfo);
-			currentSegmentInfo = undefined;
-		}
-	}
-
-	function pathEnd() {
-		currentSegmentInfo = segmentInfoStack.pop();
-	}
-
-	function segmentStart(segment) {
-		// A new CodePathSegment has started, create an "info" object to track this segments state.
-		currentSegmentInfo = {
-			ended: false,
-			prev: segment.prevSegments.map(previousSegment => segmentInfoMap.get(previousSegment.id))
-		};
-
-		segmentInfoMap.set(segment.id, currentSegmentInfo);
-	}
-
-	function segmentEnd() {
-		currentSegmentInfo = undefined;
-	}
-
-	function checkForEndExpression(node) {
-		if (isEndExpression(node) && currentSegmentInfo !== undefined) {
-			currentSegmentInfo.ended = true;
-		}
-	}
-
-	function checkStatement(node) {
-		if (!ava.isInTestFile()) {
-			return;
-		}
-
-		// If there is no current segment (this occurs in unreachable code), then we
-		// can't check whether `t.end()` was called
-		if (currentSegmentInfo === undefined) {
-			return;
-		}
-
-		const ended = [currentSegmentInfo, ...currentSegmentInfo.prev].filter(info => info.ended);
-
-		// If this segment or any previous segment is already ended, further statements are not allowed, report as an error.
-		if (ended.length > 0) {
-			for (const info of ended) {
-				// Unset ended state to avoid generating lots of errors
-				info.ended = false;
-			}
-
-			context.report({
-				node,
-				message: 'No statements following a call to `t.end()`.'
-			});
-		}
-	}
-
-	return ava.merge({
-		ExpressionStatement: checkStatement,
-		WithStatement: checkStatement,
-		IfStatement: checkStatement,
-		SwitchStatement: checkStatement,
-		ThrowStatement: checkStatement,
-		TryStatement: checkStatement,
-		WhileStatement: checkStatement,
-		DoWhileStatement: checkStatement,
-		ForStatement: checkStatement,
-		ForInStatement: checkStatement,
-		ForOfStatement: checkStatement,
-		ReturnStatement: node => {
-			// Empty return statements are OK even after `t.end`,
-			// only check it if there is an argument
-			if (node.argument) {
-				checkStatement(node);
-			}
-		},
-		onCodePathStart: pathStart,
-		onCodePathEnd: pathEnd,
-		onCodePathSegmentStart: segmentStart,
-		onCodePathSegmentEnd: segmentEnd,
-		CallExpression: checkForEndExpression
-	});
-};
-
-module.exports = {
-	create,
-	meta: {
-		docs: {
-			url: util.getDocsUrl(__filename)
-		},
-		type: 'problem'
-	}
-};
diff --git a/rules/no-todo-implementation.js b/rules/no-todo-implementation.js
index f2c94c1..5908cc4 100644
--- a/rules/no-todo-implementation.js
+++ b/rules/no-todo-implementation.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const util = require('../util');
 const createAvaRule = require('../create-ava-rule');
@@ -9,24 +8,25 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isTestNode
+			ava.isTestNode,
 		])(node => {
 			if (ava.hasTestModifier('todo') && node.arguments.some(argument => util.isFunctionExpression(argument))) {
 				context.report({
 					node,
-					message: '`test.todo()` should not be passed an implementation function.'
+					message: '`test.todo()` should not be passed an implementation function.',
 				});
 			}
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		type: 'suggestion'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/no-unknown-modifiers.js b/rules/no-unknown-modifiers.js
index f1c2f2b..32533a9 100644
--- a/rules/no-unknown-modifiers.js
+++ b/rules/no-unknown-modifiers.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const util = require('../util');
 const createAvaRule = require('../create-ava-rule');
@@ -9,12 +8,13 @@ const modifiers = new Set([
 	'always',
 	'before',
 	'beforeEach',
-	'cb',
+	'default',
 	'only',
 	'serial',
 	'skip',
 	'todo',
-	'failing'
+	'failing',
+	'macro',
 ]);
 
 const unknownModifiers = node => util.getTestModifiers(node)
@@ -26,26 +26,27 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isTestNode
+			ava.isTestNode,
 		])(node => {
 			const unknown = unknownModifiers(node);
 
 			if (unknown.length > 0) {
 				context.report({
 					node: unknown[0],
-					message: `Unknown test modifier \`.${unknown[0].name}\`.`
+					message: `Unknown test modifier \`.${unknown[0].name}\`.`,
 				});
 			}
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'problem',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		type: 'problem'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/prefer-async-await.js b/rules/prefer-async-await.js
index 8b7f9bf..812733e 100644
--- a/rules/prefer-async-await.js
+++ b/rules/prefer-async-await.js
@@ -1,19 +1,18 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const createAvaRule = require('../create-ava-rule');
 const util = require('../util');
 
 function containsThen(node) {
-	if (!node ||
-		node.type !== 'CallExpression' ||
-		node.callee.type !== 'MemberExpression'
+	if (!node
+		|| node.type !== 'CallExpression'
+		|| node.callee.type !== 'MemberExpression'
 	) {
 		return false;
 	}
 
 	const {callee} = node;
-	if (callee.property.type === 'Identifier' &&
-		callee.property.name === 'then'
+	if (callee.property.type === 'Identifier'
+		&& callee.property.name === 'then'
 	) {
 		return true;
 	}
@@ -26,7 +25,7 @@ const create = context => {
 
 	const check = visitIf([
 		ava.isInTestFile,
-		ava.isInTestNode
+		ava.isInTestNode,
 	])(node => {
 		if (node.body.type !== 'BlockStatement') {
 			return;
@@ -37,23 +36,24 @@ const create = context => {
 		if (returnStatement && containsThen(returnStatement.argument)) {
 			context.report({
 				node,
-				message: 'Prefer using async/await instead of returning a Promise.'
+				message: 'Prefer using async/await instead of returning a Promise.',
 			});
 		}
 	});
 
 	return ava.merge({
 		ArrowFunctionExpression: check,
-		FunctionExpression: check
+		FunctionExpression: check,
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		type: 'suggestion'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/prefer-power-assert.js b/rules/prefer-power-assert.js
index 9baca7d..26cbe9a 100644
--- a/rules/prefer-power-assert.js
+++ b/rules/prefer-power-assert.js
@@ -1,7 +1,6 @@
-'use strict';
+const {isDeepStrictEqual} = require('util');
 const espurify = require('espurify');
 const {visitIf} = require('enhance-visitors');
-const deepStrictEqual = require('deep-strict-equal');
 const createAvaRule = require('../create-ava-rule');
 const util = require('../util');
 
@@ -14,20 +13,20 @@ const notAllowed = [
 	'not',
 	'regex',
 	'notRegex',
-	'ifError'
+	'ifError',
 ];
 
 const assertionCalleeAst = methodName => ({
 	type: 'MemberExpression',
 	object: {
 		type: 'Identifier',
-		name: 't'
+		name: 't',
 	},
 	property: {
 		type: 'Identifier',
-		name: methodName
+		name: methodName,
 	},
-	computed: false
+	computed: false,
 });
 
 const skippedAssertionCalleeAst = methodName => ({
@@ -36,24 +35,24 @@ const skippedAssertionCalleeAst = methodName => ({
 		type: 'MemberExpression',
 		object: {
 			type: 'Identifier',
-			name: 't'
+			name: 't',
 		},
 		property: {
 			type: 'Identifier',
-			name: 'skip'
+			name: 'skip',
 		},
-		computed: false
+		computed: false,
 	},
 	property: {
 		type: 'Identifier',
-		name: methodName
+		name: methodName,
 	},
-	computed: false
+	computed: false,
 });
 
 const isCalleeMatched = (callee, methodName) =>
-	deepStrictEqual(callee, assertionCalleeAst(methodName)) ||
-	deepStrictEqual(callee, skippedAssertionCalleeAst(methodName));
+	isDeepStrictEqual(callee, assertionCalleeAst(methodName))
+	|| isDeepStrictEqual(callee, skippedAssertionCalleeAst(methodName));
 
 const create = context => {
 	const ava = createAvaRule();
@@ -61,7 +60,7 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isInTestNode
+			ava.isInTestNode,
 		])(node => {
 			const callee = espurify(node.callee);
 
@@ -70,21 +69,22 @@ const create = context => {
 					if (isCalleeMatched(callee, methodName)) {
 						context.report({
 							node,
-							message: 'Only asserts with no power-assert alternative are allowed.'
+							message: 'Only asserts with no power-assert alternative are allowed.',
 						});
 					}
 				}
 			}
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		type: 'suggestion'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/prefer-t-regex.js b/rules/prefer-t-regex.js
index 0e25d36..d96cb5c 100644
--- a/rules/prefer-t-regex.js
+++ b/rules/prefer-t-regex.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const createAvaRule = require('../create-ava-rule');
 const util = require('../util');
@@ -10,12 +9,12 @@ const create = context => {
 		'true',
 		'false',
 		'truthy',
-		'falsy'
+		'falsy',
 	]);
 
 	const equalityTests = new Set([
 		'is',
-		'deepEqual'
+		'deepEqual',
 	]);
 
 	// Find the latest reference to the given identifier's name.
@@ -120,14 +119,14 @@ const create = context => {
 			const source = context.getSourceCode();
 			return [
 				fixer.replaceText(node.callee.property, assertion),
-				fixer.replaceText(firstArg, `${source.getText(variable)}, ${source.getText(lookup)}`)
+				fixer.replaceText(firstArg, `${source.getText(variable)}, ${source.getText(lookup)}`),
 			];
 		};
 
 		context.report({
 			node,
 			message: `Prefer using the \`t.${assertion}()\` assertion.`,
-			fix
+			fix,
 		});
 	};
 
@@ -150,7 +149,7 @@ const create = context => {
 			return [
 				fixer.replaceText(node.callee.property, assertion),
 				fixer.replaceText(firstArg, `${source.getText(regex.arguments[0])}`),
-				fixer.replaceText(secondArg, `${source.getText(regex.callee.object)}`)
+				fixer.replaceText(secondArg, `${source.getText(regex.callee.object)}`),
 			];
 		};
 
@@ -169,7 +168,7 @@ const create = context => {
 			context.report({
 				node,
 				message: `Prefer using the \`t.${assertion}()\` assertion.`,
-				fix: booleanFixer(assertion)
+				fix: booleanFixer(assertion),
 			});
 		}
 	};
@@ -177,33 +176,34 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isInTestNode
+			ava.isInTestNode,
 		])(node => {
-			const isAssertion = node.callee.type === 'MemberExpression' &&
-				util.getNameOfRootNodeObject(node.callee) === 't';
+			const isAssertion = node.callee.type === 'MemberExpression'
+				&& util.getNameOfRootNodeObject(node.callee) === 't';
 
-			const isBooleanAssertion = isAssertion &&
-				booleanTests.has(node.callee.property.name);
+			const isBooleanAssertion = isAssertion
+				&& booleanTests.has(node.callee.property.name);
 
-			const isEqualityAssertion = isAssertion &&
-				equalityTests.has(node.callee.property.name);
+			const isEqualityAssertion = isAssertion
+				&& equalityTests.has(node.callee.property.name);
 
 			if (isBooleanAssertion) {
 				booleanHandler(node);
 			} else if (isEqualityAssertion) {
 				equalityHandler(node);
 			}
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
 		fixable: 'code',
-		type: 'suggestion'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/use-t-throws-async-well.js b/rules/use-t-throws-async-well.js
index 16ff098..deb9ba6 100644
--- a/rules/use-t-throws-async-well.js
+++ b/rules/use-t-throws-async-well.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const util = require('../util');
 const createAvaRule = require('../create-ava-rule');
@@ -9,39 +8,40 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isInTestNode
+			ava.isInTestNode,
 		])(node => {
 			if (
-				node.parent.type === 'ExpressionStatement' &&
-				node.callee.type === 'MemberExpression' &&
-				(node.callee.property.name === 'throwsAsync' || node.callee.property.name === 'notThrowsAsync') &&
-				node.callee.object.name === 't'
+				node.parent.type === 'ExpressionStatement'
+				&& node.callee.type === 'MemberExpression'
+				&& (node.callee.property.name === 'throwsAsync' || node.callee.property.name === 'notThrowsAsync')
+				&& node.callee.object.name === 't'
 			) {
 				const message = `Use \`await\` with \`t.${node.callee.property.name}()\`.`;
 				if (ava.isInTestNode().arguments[0].async) {
 					context.report({
 						node,
 						message,
-						fix: fixer => fixer.replaceText(node.callee, `await ${context.getSourceCode().getText(node.callee)}`)
+						fix: fixer => fixer.replaceText(node.callee, `await ${context.getSourceCode().getText(node.callee)}`),
 					});
 				} else {
 					context.report({
 						node,
-						message
+						message,
 					});
 				}
 			}
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'problem',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
 		fixable: 'code',
-		type: 'problem'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/use-t-well.js b/rules/use-t-well.js
index 3409dff..339329e 100644
--- a/rules/use-t-well.js
+++ b/rules/use-t-well.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const MicroSpellingCorrecter = require('micro-spelling-correcter');
 
@@ -9,14 +8,14 @@ const properties = new Set([
 	...util.executionMethods,
 	'context',
 	'title',
-	'skip'
+	'skip',
 ]);
 
 const correcter = new MicroSpellingCorrecter([...properties]);
 
 const isCallExpression = node =>
-	node.parent.type === 'CallExpression' &&
-	node.parent.callee === node;
+	node.parent.type === 'CallExpression'
+	&& node.parent.callee === node;
 
 const getMemberNodes = node => {
 	if (node.object.type === 'MemberExpression') {
@@ -32,22 +31,22 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isInTestNode
+			ava.isInTestNode,
 		])(node => {
-			if (node.callee.type !== 'MemberExpression' &&
-					node.callee.name === 't') {
+			if (node.callee.type !== 'MemberExpression'
+					&& node.callee.name === 't') {
 				context.report({
 					node,
-					message: '`t` is not a function.'
+					message: '`t` is not a function.',
 				});
 			}
 		}),
 		MemberExpression: visitIf([
 			ava.isInTestFile,
-			ava.isInTestNode
+			ava.isInTestNode,
 		])(node => {
-			if (node.parent.type === 'MemberExpression' ||
-					util.getNameOfRootNodeObject(node) !== 't') {
+			if (node.parent.type === 'MemberExpression'
+					|| util.getNameOfRootNodeObject(node) !== 't') {
 				return;
 			}
 
@@ -69,19 +68,19 @@ const create = context => {
 						if (isCallExpression(node)) {
 							context.report({
 								node,
-								message: `Unknown assertion method \`.${name}\`.`
+								message: `Unknown assertion method \`.${name}\`.`,
 							});
 						} else {
 							context.report({
 								node,
-								message: `Unknown member \`.${name}\`. Use \`.context.${name}\` instead.`
+								message: `Unknown member \`.${name}\`. Use \`.context.${name}\` instead.`,
 							});
 						}
 					} else {
 						context.report({
 							node,
 							message: `Misspelled \`.${corrected}\` as \`.${name}\`.`,
-							fix: fixer => fixer.replaceText(member, corrected)
+							fix: fixer => fixer.replaceText(member, corrected),
 						});
 					}
 
@@ -92,7 +91,7 @@ const create = context => {
 					if (members.length === 1 && isCallExpression(node)) {
 						context.report({
 							node,
-							message: `Unknown assertion method \`.${name}\`.`
+							message: `Unknown assertion method \`.${name}\`.`,
 						});
 					}
 
@@ -105,7 +104,7 @@ const create = context => {
 					if (hadCall) {
 						context.report({
 							node,
-							message: 'Can\'t chain assertion methods.'
+							message: 'Can\'t chain assertion methods.',
 						});
 					}
 
@@ -116,7 +115,7 @@ const create = context => {
 			if (!hadCall) {
 				context.report({
 					node,
-					message: 'Missing assertion method.'
+					message: 'Missing assertion method.',
 				});
 			}
 
@@ -127,7 +126,7 @@ const create = context => {
 					fix: fixer => {
 						const chain = ['t', ...members.map(member => member.name).filter(name => name !== 'skip'), 'skip'];
 						return fixer.replaceText(node, chain.join('.'));
-					}
+					},
 				});
 			}
 
@@ -138,20 +137,21 @@ const create = context => {
 					fix: fixer => {
 						const chain = ['t', ...members.map(member => member.name).filter(name => name !== 'skip'), 'skip'];
 						return fixer.replaceText(node, chain.join('.'));
-					}
+					},
 				});
 			}
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'problem',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
 		fixable: 'code',
-		type: 'problem'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/use-t.js b/rules/use-t.js
index 70940f4..04d7e84 100644
--- a/rules/use-t.js
+++ b/rules/use-t.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const createAvaRule = require('../create-ava-rule');
 const util = require('../util');
@@ -9,40 +8,40 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isTestNode
+			ava.isTestNode,
 		])(node => {
-			const functionArgIndex = node.arguments.length - 1;
-			if (functionArgIndex > 1) {
+			const index = node.arguments.length - 1;
+			if (index > 1) {
 				return;
 			}
 
-			const functionArg = node.arguments[functionArgIndex];
+			let implementationArg = node.arguments[index];
+			if (ava.hasTestModifier('macro') && implementationArg.type === 'ObjectExpression') {
+				const execProperty = implementationArg.properties.find(p => p.key.name === 'exec');
+				implementationArg = execProperty && execProperty.value;
+			}
 
-			if (!(functionArg && functionArg.params && functionArg.params.length > 0)) {
+			if (!implementationArg || !implementationArg.params || implementationArg.params.length === 0) {
 				return;
 			}
 
-			if (functionArg.params.length > 1) {
-				context.report({
-					node,
-					message: 'Test should only have one parameter named `t`.'
-				});
-			} else if (functionArg.params[0].name !== 't') {
+			if (implementationArg.params[0].name !== 't') {
 				context.report({
 					node,
-					message: 'Test parameter should be named `t`.'
+					message: 'Test parameter should be named `t`.',
 				});
 			}
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		type: 'suggestion'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/use-true-false.js b/rules/use-true-false.js
index 8913a91..1aa06e9 100644
--- a/rules/use-true-false.js
+++ b/rules/use-true-false.js
@@ -1,8 +1,7 @@
-'use strict';
+const {isDeepStrictEqual} = require('util');
 const espree = require('espree');
 const espurify = require('espurify');
 const {visitIf} = require('enhance-visitors');
-const deepStrictEqual = require('deep-strict-equal');
 const util = require('../util');
 const createAvaRule = require('../create-ava-rule');
 
@@ -14,7 +13,7 @@ const booleanBinaryOperators = new Set([
 	'<',
 	'<=',
 	'>',
-	'>='
+	'>=',
 ]);
 
 const knownBooleanSignatures = [
@@ -33,7 +32,7 @@ const knownBooleanSignatures = [
 	'ArrayBuffer.isView()',
 	'SharedArrayBuffer.isView()',
 	'Reflect.has()',
-	'Reflect.isExtensible()'
+	'Reflect.isExtensible()',
 ].map(signature => espurify(espree.parse(signature).body[0].expression.callee));
 
 function matchesKnownBooleanExpression(argument) {
@@ -43,7 +42,7 @@ function matchesKnownBooleanExpression(argument) {
 
 	const callee = espurify(argument.callee);
 
-	return knownBooleanSignatures.some(signature => deepStrictEqual(callee, signature));
+	return knownBooleanSignatures.some(signature => isDeepStrictEqual(callee, signature));
 }
 
 const create = context => {
@@ -52,44 +51,45 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isInTestNode
+			ava.isInTestNode,
 		])(node => {
 			if (
-				node.callee.type === 'MemberExpression' &&
-				(node.callee.property.name === 'truthy' || node.callee.property.name === 'falsy') &&
-				node.callee.object.name === 't'
+				node.callee.type === 'MemberExpression'
+				&& (node.callee.property.name === 'truthy' || node.callee.property.name === 'falsy')
+				&& node.callee.object.name === 't'
 			) {
 				const argument = node.arguments[0];
 
-				if (argument &&
-					((argument.type === 'BinaryExpression' && booleanBinaryOperators.has(argument.operator)) ||
-					(argument.type === 'UnaryExpression' && argument.operator === '!') ||
-					(argument.type === 'Literal' && argument.value === Boolean(argument.value)) ||
-					(matchesKnownBooleanExpression(argument)))
+				if (argument
+					&& ((argument.type === 'BinaryExpression' && booleanBinaryOperators.has(argument.operator))
+					|| (argument.type === 'UnaryExpression' && argument.operator === '!')
+					|| (argument.type === 'Literal' && argument.value === Boolean(argument.value))
+					|| (matchesKnownBooleanExpression(argument)))
 				) {
 					if (node.callee.property.name === 'falsy') {
 						context.report({
 							node,
-							message: '`t.false()` should be used instead of `t.falsy()`.'
+							message: '`t.false()` should be used instead of `t.falsy()`.',
 						});
 					} else {
 						context.report({
 							node,
-							message: '`t.true()` should be used instead of `t.truthy()`.'
+							message: '`t.true()` should be used instead of `t.truthy()`.',
 						});
 					}
 				}
 			}
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		type: 'suggestion'
-	}
+		schema: [],
+	},
 };
diff --git a/util.js b/util.js
index def6dd1..e251f94 100644
--- a/util.js
+++ b/util.js
@@ -1,4 +1,3 @@
-'use strict';
 const path = require('path');
 const pkgDir = require('pkg-dir');
 const resolveFrom = require('resolve-from');
@@ -21,7 +20,7 @@ exports.loadAvaHelper = (filename, overrides) => {
 
 const functionExpressions = new Set([
 	'FunctionExpression',
-	'ArrowFunctionExpression'
+	'ArrowFunctionExpression',
 ]);
 
 exports.getRootNode = node => {
@@ -32,13 +31,9 @@ exports.getRootNode = node => {
 	return node;
 };
 
-exports.getNameOfRootNodeObject = node => {
-	return exports.getRootNode(node).object.name;
-};
+exports.getNameOfRootNodeObject = node => exports.getRootNode(node).object.name;
 
-exports.isPropertyUnderContext = node => {
-	return exports.getRootNode(node).property.name === 'context';
-};
+exports.isPropertyUnderContext = node => exports.getRootNode(node).property.name === 'context';
 
 exports.isFunctionExpression = node => node && functionExpressions.has(node.type);
 
@@ -56,13 +51,11 @@ function getTestModifiers(node) {
 
 exports.getTestModifiers = getTestModifiers;
 
-exports.getTestModifier = (node, mod) => {
-	return getTestModifiers(node).find(property => property.name === mod);
-};
+exports.getTestModifier = (node, mod) => getTestModifiers(node).find(property => property.name === mod);
 
 exports.removeTestModifier = parameters => {
 	const modifier = parameters.modifier.trim();
-	const range = exports.getTestModifier(parameters.node, modifier).range.slice();
+	const range = [...exports.getTestModifier(parameters.node, modifier).range];
 	const replacementRegExp = new RegExp(`\\.|${modifier}`, 'g');
 	const source = parameters.context.getSourceCode().getText();
 	let dotPosition = range[0] - 1;
@@ -118,7 +111,7 @@ const assertionMethodsNumberArguments = new Map([
 	['throwsAsync', 1],
 	['true', 1],
 	['truthy', 1],
-	['try', 1]
+	['try', 1],
 ]);
 
 const assertionMethodNames = [...assertionMethodsNumberArguments.keys()];


Test patch:
diff --git a/docs/rules/no-cb-test.md b/docs/rules/no-cb-test.md
deleted file mode 100644
index 7ff8a38..0000000
--- a/docs/rules/no-cb-test.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# Ensure no `test.cb()` is used
-
-Translations: [Français](https://github.com/avajs/ava-docs/blob/main/fr_FR/related/eslint-plugin-ava/docs/rules/no-cb-test.md)
-
-Disallow the use of `test.cb()`. We instead recommend using `test()` with an async function or a function returning a promise.
-
-## Fail
-
-```js
-const test = require('ava');
-
-test.cb('some test', t => {
-	t.pass();
-	t.end();
-});
-```
-
-## Pass
-
-```js
-const test = require('ava');
-
-test('some test', async t => {
-	t.pass();
-});
-```
diff --git a/docs/rules/test-ended.md b/docs/rules/test-ended.md
deleted file mode 100644
index f2252f4..0000000
--- a/docs/rules/test-ended.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# Ensure callback tests are explicitly ended
-
-Translations: [Français](https://github.com/avajs/ava-docs/blob/main/fr_FR/related/eslint-plugin-ava/docs/rules/test-ended.md)
-
-If you forget a `t.end();` in `test.cb()` the test will hang indefinitely.
-
-## Fail
-
-```js
-const test = require('ava');
-
-test.cb(t => {
-	t.pass();
-});
-```
-
-## Pass
-
-```js
-const test = require('ava');
-
-test.cb(t => {
-	t.pass();
-	t.end();
-});
-
-test.cb(t => {
-	acceptsCallback(t.end);
-});
-```
diff --git a/rules/no-cb-test.js b/rules/no-cb-test.js
deleted file mode 100644
index 6731029..0000000
--- a/rules/no-cb-test.js
+++ /dev/null
@@ -1,32 +0,0 @@
-'use strict';
-const {visitIf} = require('enhance-visitors');
-const createAvaRule = require('../create-ava-rule');
-const util = require('../util');
-
-const create = context => {
-	const ava = createAvaRule();
-
-	return ava.merge({
-		CallExpression: visitIf([
-			ava.isInTestFile,
-			ava.isTestNode
-		])(node => {
-			if (ava.hasTestModifier('cb')) {
-				context.report({
-					node: util.getTestModifier(node, 'cb'),
-					message: '`test.cb()` should not be used.'
-				});
-			}
-		})
-	});
-};
-
-module.exports = {
-	create,
-	meta: {
-		docs: {
-			url: util.getDocsUrl(__filename)
-		},
-		type: 'suggestion'
-	}
-};
diff --git a/rules/no-ignored-test-files.js b/rules/no-ignored-test-files.js
index 203fd08..e97ca25 100644
--- a/rules/no-ignored-test-files.js
+++ b/rules/no-ignored-test-files.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const util = require('../util');
 const createAvaRule = require('../create-ava-rule');
@@ -17,7 +16,7 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isTestNode
+			ava.isTestNode,
 		])(() => {
 			hasTestCall = true;
 		}),
@@ -42,7 +41,7 @@ const create = context => {
 			}
 
 			hasTestCall = false;
-		}
+		},
 	});
 };
 
@@ -50,24 +49,24 @@ const schema = [{
 	type: 'object',
 	properties: {
 		extensions: {
-			type: 'array'
+			type: 'array',
 		},
 		files: {
-			type: 'array'
+			type: 'array',
 		},
 		helpers: {
-			type: 'array'
-		}
-	}
+			type: 'array',
+		},
+	},
 }];
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
 		schema,
-		type: 'suggestion'
-	}
+	},
 };
diff --git a/rules/no-import-test-files.js b/rules/no-import-test-files.js
index ca7c495..9aac59b 100644
--- a/rules/no-import-test-files.js
+++ b/rules/no-import-test-files.js
@@ -1,4 +1,3 @@
-'use strict';
 const path = require('path');
 const util = require('../util');
 
@@ -40,7 +39,7 @@ const create = context => {
 		if (isTest) {
 			context.report({
 				node,
-				message: 'Test files should not be imported.'
+				message: 'Test files should not be imported.',
 			});
 		}
 	};
@@ -57,7 +56,7 @@ const create = context => {
 			if (node.arguments[0]) {
 				validateImportPath(node, node.arguments[0].value);
 			}
-		}
+		},
 	};
 };
 
@@ -65,21 +64,21 @@ const schema = [{
 	type: 'object',
 	properties: {
 		extensions: {
-			type: 'array'
+			type: 'array',
 		},
 		files: {
-			type: 'array'
-		}
-	}
+			type: 'array',
+		},
+	},
 }];
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
 		schema,
-		type: 'suggestion'
-	}
+	},
 };
diff --git a/rules/no-nested-tests.js b/rules/no-nested-tests.js
index 7806140..e3ddbd8 100644
--- a/rules/no-nested-tests.js
+++ b/rules/no-nested-tests.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const createAvaRule = require('../create-ava-rule');
 const util = require('../util');
@@ -10,32 +9,33 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isTestNode
+			ava.isTestNode,
 		])(node => {
 			nestedCount++;
 			if (nestedCount >= 2) {
 				context.report({
 					node,
-					message: 'Tests should not be nested.'
+					message: 'Tests should not be nested.',
 				});
 			}
 		}),
 
 		'CallExpression:exit': visitIf([
 			ava.isInTestFile,
-			ava.isTestNode
+			ava.isTestNode,
 		])(() => {
 			nestedCount--;
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'problem',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		type: 'problem'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/no-only-test.js b/rules/no-only-test.js
index f0a0dc6..a711e8a 100644
--- a/rules/no-only-test.js
+++ b/rules/no-only-test.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const createAvaRule = require('../create-ava-rule');
 const util = require('../util');
@@ -9,7 +8,7 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isTestNode
+			ava.isTestNode,
 		])(node => {
 			const propertyNode = util.getTestModifier(node, 'only');
 			if (propertyNode) {
@@ -18,27 +17,26 @@ const create = context => {
 					message: '`test.only()` should not be used.',
 					suggest: [{
 						desc: 'Remove the `.only`',
-						fix: fixer => {
-							return fixer.replaceTextRange.apply(null, util.removeTestModifier({
-								modifier: 'only',
-								node,
-								context
-							}));
-						}
-					}]
+						fix: fixer => fixer.replaceTextRange.apply(null, util.removeTestModifier({
+							modifier: 'only',
+							node,
+							context,
+						})),
+					}],
 				});
 			}
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
 		fixable: 'code',
-		type: 'suggestion'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/no-skip-test.js b/rules/no-skip-test.js
index ae9379b..c839bdd 100644
--- a/rules/no-skip-test.js
+++ b/rules/no-skip-test.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const createAvaRule = require('../create-ava-rule');
 const util = require('../util');
@@ -9,7 +8,7 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isTestNode
+			ava.isTestNode,
 		])(node => {
 			const propertyNode = util.getTestModifier(node, 'skip');
 			if (propertyNode) {
@@ -18,27 +17,26 @@ const create = context => {
 					message: 'No tests should be skipped.',
 					suggest: [{
 						desc: 'Remove the `.skip`',
-						fix: fixer => {
-							return fixer.replaceTextRange.apply(null, util.removeTestModifier({
-								modifier: 'skip',
-								node,
-								context
-							}));
-						}
-					}]
+						fix: fixer => fixer.replaceTextRange.apply(null, util.removeTestModifier({
+							modifier: 'skip',
+							node,
+							context,
+						})),
+					}],
 				});
 			}
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
 		fixable: 'code',
-		type: 'suggestion'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/no-todo-test.js b/rules/no-todo-test.js
index e36bd9e..5a5a89e 100644
--- a/rules/no-todo-test.js
+++ b/rules/no-todo-test.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const createAvaRule = require('../create-ava-rule');
 const util = require('../util');
@@ -9,24 +8,25 @@ const create = context => {
 	return ava.merge({
 		CallExpression: visitIf([
 			ava.isInTestFile,
-			ava.isTestNode
+			ava.isTestNode,
 		])(node => {
 			if (ava.hasTestModifier('todo')) {
 				context.report({
 					node,
-					message: '`test.todo()` should not be used.'
+					message: '`test.todo()` should not be used.',
 				});
 			}
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		type: 'suggestion'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/test-ended.js b/rules/test-ended.js
deleted file mode 100644
index c874ce9..0000000
--- a/rules/test-ended.js
+++ /dev/null
@@ -1,63 +0,0 @@
-'use strict';
-const {visitIf} = require('enhance-visitors');
-const createAvaRule = require('../create-ava-rule');
-const util = require('../util');
-
-const create = context => {
-	const ava = createAvaRule();
-	const hasCbModifier = () => ava.hasTestModifier('cb');
-	let endCalled = false;
-
-	return ava.merge({
-		MemberExpression: visitIf([
-			ava.isInTestFile,
-			ava.isInTestNode,
-			hasCbModifier
-		])(node => {
-			if (node.object.name === 't' &&
-				node.property.name === 'end'
-			) {
-				endCalled = true;
-			}
-		}),
-		CallExpression: visitIf([
-			ava.isInTestFile,
-			ava.isTestNode,
-			hasCbModifier
-		])(node => {
-			const firstArg = node.arguments[0];
-			if (node.callee.property.name === 'cb' && firstArg.type === 'Identifier') {
-				const scope = context.getScope();
-				const exists = scope.references.some(ref => ref.identifier.name === firstArg.name);
-				if (exists) {
-					endCalled = true;
-				}
-			}
-		}),
-		'CallExpression:exit': visitIf([
-			ava.isInTestFile,
-			ava.isTestNode,
-			hasCbModifier
-		])(node => {
-			// Leaving test function
-			if (endCalled) {
-				endCalled = false;
-			} else {
-				context.report({
-					node,
-					message: 'Callback test was not ended. Make sure to explicitly end the test with `t.end()`.'
-				});
-			}
-		})
-	});
-};
-
-module.exports = {
-	create,
-	meta: {
-		docs: {
-			url: util.getDocsUrl(__filename)
-		},
-		type: 'problem'
-	}
-};
diff --git a/rules/test-title-format.js b/rules/test-title-format.js
index 378f025..fd2b047 100644
--- a/rules/test-title-format.js
+++ b/rules/test-title-format.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const createAvaRule = require('../create-ava-rule');
 const util = require('../util');
@@ -17,7 +16,7 @@ const create = context => {
 		CallExpression: visitIf([
 			ava.isInTestFile,
 			ava.isTestNode,
-			ava.hasNoHookModifier
+			ava.hasNoUtilityModifier,
 		])(node => {
 			const requiredLength = ava.hasTestModifier('todo') ? 1 : 2;
 			const hasTitle = node.arguments.length >= requiredLength;
@@ -27,11 +26,11 @@ const create = context => {
 				if (title.type === 'Literal' && !titleRegExp.test(title.value)) {
 					context.report({
 						node,
-						message: `The test title doesn't match the required format: \`${titleRegExp}\`.`
+						message: `The test title doesn't match the required format: \`${titleRegExp}\`.`,
 					});
 				}
 			}
-		})
+		}),
 	});
 };
 
@@ -41,10 +40,10 @@ const schema = [
 		properties: {
 			format: {
 				type: 'string',
-				default: undefined
-			}
-		}
-	}
+				default: undefined,
+			},
+		},
+	},
 ];
 
 module.exports = {
@@ -52,8 +51,8 @@ module.exports = {
 	meta: {
 		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		schema
-	}
+		schema,
+	},
 };
diff --git a/rules/test-title.js b/rules/test-title.js
index e0c1623..0349b87 100644
--- a/rules/test-title.js
+++ b/rules/test-title.js
@@ -1,4 +1,3 @@
-'use strict';
 const {visitIf} = require('enhance-visitors');
 const createAvaRule = require('../create-ava-rule');
 const util = require('../util');
@@ -10,26 +9,27 @@ const create = context => {
 		CallExpression: visitIf([
 			ava.isInTestFile,
 			ava.isTestNode,
-			ava.hasNoHookModifier
+			ava.hasNoUtilityModifier,
 		])(node => {
 			const firstArgumentIsFunction = node.arguments.length === 0 || util.isFunctionExpression(node.arguments[0]);
 
 			if (firstArgumentIsFunction) {
 				context.report({
 					node,
-					message: 'Test should have a title.'
+					message: 'Test should have a title.',
 				});
 			}
-		})
+		}),
 	});
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'problem',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		type: 'problem'
-	}
+		schema: [],
+	},
 };
diff --git a/rules/use-test.js b/rules/use-test.js
index 432343f..a0b3746 100644
--- a/rules/use-test.js
+++ b/rules/use-test.js
@@ -1,27 +1,26 @@
-'use strict';
 const path = require('path');
+const {isDeepStrictEqual} = require('util');
 const espurify = require('espurify');
-const deepStrictEqual = require('deep-strict-equal');
 const util = require('../util');
 
 const avaVariableDeclaratorInitAst = {
 	type: 'CallExpression',
 	callee: {
 		type: 'Identifier',
-		name: 'require'
+		name: 'require',
 	},
 	arguments: [
 		{
 			type: 'Literal',
-			value: 'ava'
-		}
-	]
+			value: 'ava',
+		},
+	],
 };
 
 function report(context, node) {
 	context.report({
 		node,
-		message: 'AVA should be imported as `test`.'
+		message: 'AVA should be imported as `test`.',
 	});
 }
 
@@ -39,22 +38,23 @@ const create = context => {
 			}
 		},
 		VariableDeclarator: node => {
-			if (node.init && deepStrictEqual(espurify(node.init), avaVariableDeclaratorInitAst)) {
+			if (node.init && isDeepStrictEqual(espurify(node.init), avaVariableDeclaratorInitAst)) {
 				const {name} = node.id;
 				if (name !== 'test' && (!isTypeScript || name !== 'anyTest')) {
 					report(context, node);
 				}
 			}
-		}
+		},
 	};
 };
 
 module.exports = {
 	create,
 	meta: {
+		type: 'suggestion',
 		docs: {
-			url: util.getDocsUrl(__filename)
+			url: util.getDocsUrl(__filename),
 		},
-		type: 'suggestion'
-	}
+		schema: [],
+	},
 };
diff --git a/test/assertion-arguments.js b/test/assertion-arguments.js
index 4b51147..18e85c5 100644
--- a/test/assertion-arguments.js
+++ b/test/assertion-arguments.js
@@ -4,11 +4,11 @@ const rule = require('../rules/assertion-arguments');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
+		es6: true,
 	},
 	parserOptions: {
-		ecmaVersion: 2021
-	}
+		ecmaVersion: 2021,
+	},
 });
 
 const missingError = 'Expected an assertion message, but found none.';
@@ -17,7 +17,7 @@ const tooFewError = n => `Not enough arguments. Expected at least ${n}.`;
 const tooManyError = n => `Too many arguments. Expected at most ${n}.`;
 const outOfOrderError = (line, column, endLine, endColumn) => ({
 	message: 'Expected values should come after actual values.',
-	line, column, endLine, endColumn
+	line, column, endLine, endColumn,
 });
 const messageIsNotStringError = 'Assertion message should be a string.';
 
@@ -56,7 +56,7 @@ function offsetError(error, line, column) {
 }
 
 function testCase(message, content, errors = [], {
-	useHeader, output = null
+	useHeader, output = null,
 } = {}) {
 	if (!Array.isArray(errors)) {
 		errors = [errors];
@@ -72,7 +72,7 @@ function testCase(message, content, errors = [], {
 		errors,
 		options: message ? [{message}] : [],
 		code: testCode(content, useHeader),
-		output: output === null ? null : testCode(output, useHeader)
+		output: output === null ? null : testCode(output, useHeader),
 	};
 }
 
@@ -115,7 +115,7 @@ const statics = [
 	'[[1]][0][0]',
 	'{a: 1}?.a?.["b"]',
 	'[{a: 1}]?.a?.[0]',
-	'a = 1'
+	'a = 1',
 ];
 
 const dynamics = [
@@ -151,7 +151,7 @@ const dynamics = [
 	'a ? [] : [1]',
 	'true ? a : [1]',
 	'"a"?.()',
-	'{a: 1}?.[b]'
+	'{a: 1}?.[b]',
 ];
 
 ruleTester.run('assertion-arguments', rule, {
@@ -336,7 +336,7 @@ ruleTester.run('assertion-arguments', rule, {
 
 		// Lookup message type
 		testCase(false, 'const message = \'ok\'; t.assert(true, message);'),
-		testCase(false, 'const message = \'ok\'; t.is(42, 42, message);')
+		testCase(false, 'const message = \'ok\'; t.is(42, 42, message);'),
 	],
 	invalid: [
 		// Not enough arguments
@@ -447,57 +447,57 @@ ruleTester.run('assertion-arguments', rule, {
 		// Assertion argument order
 		testCase(false, 't.deepEqual(\'static\', dynamic);',
 			outOfOrderError(1, 13, 1, 30),
-			{output: 't.deepEqual(dynamic, \'static\');'}
+			{output: 't.deepEqual(dynamic, \'static\');'},
 		),
 		testCase(false, 't.is(\'static\', dynamic);',
 			outOfOrderError(1, 6, 1, 23),
-			{output: 't.is(dynamic, \'static\');'}
+			{output: 't.is(dynamic, \'static\');'},
 		),
 		testCase(false, 't.like({a: {b: 1}}, dynamic);',
 			outOfOrderError(1, 8, 1, 28),
-			{output: 't.like(dynamic, {a: {b: 1}});'}
+			{output: 't.like(dynamic, {a: {b: 1}});'},
 		),
 		testCase(false, 't.not(\'static\', dynamic);',
 			outOfOrderError(1, 7, 1, 24),
-			{output: 't.not(dynamic, \'static\');'}
+			{output: 't.not(dynamic, \'static\');'},
 		),
 		testCase(false, 't.notDeepEqual({static: true}, dynamic);',
 			outOfOrderError(1, 16, 1, 39),
-			{output: 't.notDeepEqual(dynamic, {static: true});'}
+			{output: 't.notDeepEqual(dynamic, {static: true});'},
 		),
 		testCase(false, 't.throws({name: \'TypeError\'}, () => {});',
 			outOfOrderError(1, 10, 1, 39),
-			{output: 't.throws(() => {}, {name: \'TypeError\'});'}
+			{output: 't.throws(() => {}, {name: \'TypeError\'});'},
 		),
 		testCase(false, 't.throwsAsync({name: \'TypeError\'}, async () => {});',
 			outOfOrderError(1, 15, 1, 50),
-			{output: 't.throwsAsync(async () => {}, {name: \'TypeError\'});'}
+			{output: 't.throwsAsync(async () => {}, {name: \'TypeError\'});'},
 		),
 		testCase('always', 't.deepEqual({}, actual, \'message\');',
 			outOfOrderError(1, 13, 1, 23),
-			{output: 't.deepEqual(actual, {}, \'message\');'}
+			{output: 't.deepEqual(actual, {}, \'message\');'},
 		),
 		testCase('never', 't.deepEqual({}, actual);',
 			outOfOrderError(1, 13, 1, 23),
-			{output: 't.deepEqual(actual, {});'}
+			{output: 't.deepEqual(actual, {});'},
 		),
 		testCase('always', 't.deepEqual({}, actual);',
 			[missingError, outOfOrderError(1, 13, 1, 23)],
-			{output: 't.deepEqual(actual, {});'}
+			{output: 't.deepEqual(actual, {});'},
 		),
 		testCase('never', 't.deepEqual({}, actual, \'message\');',
 			[foundError, outOfOrderError(1, 13, 1, 23)],
-			{output: 't.deepEqual(actual, {}, \'message\');'}
+			{output: 't.deepEqual(actual, {}, \'message\');'},
 		),
 		testCase(false, 't.deepEqual({}, actual, extra, \'message\');',
-			tooManyError(3)
+			tooManyError(3),
 		),
 		testCase(false, 't.deepEqual({}, (actual));',
 			outOfOrderError(1, 13, 1, 25),
-			{output: 't.deepEqual((actual), {});'}
+			{output: 't.deepEqual((actual), {});'},
 		),
 		testCase(false, 't.deepEqual({}, actual/*: type */);',
-			outOfOrderError(1, 13, 1, 34)
+			outOfOrderError(1, 13, 1, 34),
 		),
 		testCase(
 			false,
@@ -507,48 +507,48 @@ ruleTester.run('assertion-arguments', rule, {
 				dynamic // Line Comment 4
 				// Line Comment 5
 			); // Line Comment 6`,
-			outOfOrderError(1, 13, 5, 22)
+			outOfOrderError(1, 13, 5, 22),
 		),
 		testCase(false, 't.assert(\'static\' !== dynamic);',
 			outOfOrderError(1, 10, 1, 30),
-			{output: 't.assert(dynamic !== \'static\');'}
+			{output: 't.assert(dynamic !== \'static\');'},
 		),
 		testCase(false, 't.true(\'static\' <= dynamic);',
 			outOfOrderError(1, 8, 1, 27),
-			{output: 't.true(dynamic >= \'static\');'}
+			{output: 't.true(dynamic >= \'static\');'},
 		),
 		testCase(false, 't.false(\'static\' < dynamic);',
 			outOfOrderError(1, 9, 1, 27),
-			{output: 't.false(dynamic > \'static\');'}
+			{output: 't.false(dynamic > \'static\');'},
 		),
 		testCase(false, 't.truthy(\'static\' > dynamic);',
 			outOfOrderError(1, 10, 1, 28),
-			{output: 't.truthy(dynamic < \'static\');'}
+			{output: 't.truthy(dynamic < \'static\');'},
 		),
 		testCase(false, 't.falsy(\'static\' >= dynamic);',
 			outOfOrderError(1, 9, 1, 28),
-			{output: 't.falsy(dynamic <= \'static\');'}
+			{output: 't.falsy(dynamic <= \'static\');'},
 		),
 		testCase(false, 't.true(\'static\' === actual/*: type */);',
-			outOfOrderError(1, 8, 1, 38)
+			outOfOrderError(1, 8, 1, 38),
 		),
 		...statics.map(expression =>
 			testCase(false, `t.deepEqual(${expression}, dynamic);`,
 				outOfOrderError(1, 13, 1, 22 + expression.length),
-				{output: `t.deepEqual(dynamic, ${expression});`}
-			)
+				{output: `t.deepEqual(dynamic, ${expression});`},
+			),
 		),
 		...dynamics.map(expression =>
 			testCase(false, `t.deepEqual('static', ${expression});`,
 				outOfOrderError(1, 13, 1, 23 + expression.length),
-				{output: `t.deepEqual(${expression}, 'static');`}
-			)
+				{output: `t.deepEqual(${expression}, 'static');`},
+			),
 		),
 
 		// Message is not string
 		testCase(false, 't.assert(true, true);', messageIsNotStringError),
 		testCase(false, 't.deepEqual({}, {}, 42);', messageIsNotStringError),
 		testCase(false, 't.fail({});', messageIsNotStringError),
-		testCase(false, 'let message = "ok"; message = false; t.assert(true, message);', messageIsNotStringError)
-	]
+		testCase(false, 'let message = "ok"; message = false; t.assert(true, message);', messageIsNotStringError),
+	],
 });
diff --git a/test/create-ava-rule.js b/test/create-ava-rule.js
index 897a275..a93b252 100644
--- a/test/create-ava-rule.js
+++ b/test/create-ava-rule.js
@@ -11,24 +11,24 @@ const rule = {
 				if (!ava.isInTestFile()) {
 					context.report({node, message: 'not a test file'});
 				}
-			}
+			},
 		});
-	}
+	},
 };
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
+		es6: true,
 	},
 	parserOptions: {
-		sourceType: 'module'
-	}
+		sourceType: 'module',
+	},
 });
 
 const errors = [
 	{
-		message: 'not a test file'
-	}
+		message: 'not a test file',
+	},
 ];
 
 ruleTester.run('rule-fixture', rule, {
@@ -38,33 +38,33 @@ ruleTester.run('rule-fixture', rule, {
 		'const {serial: test} = require(\'ava\');',
 		'import test from \'ava\';',
 		'import {serial} from \'ava\';',
-		'import {serial as test} from \'ava\';'
+		'import {serial as test} from \'ava\';',
 	],
 
 	invalid: [
 		{
 			code: 'const test2 = require(\'ava\');',
-			errors
+			errors,
 		},
 		{
 			code: 'const {serial2} = require(\'ava\');',
-			errors
+			errors,
 		},
 		{
 			code: 'const {serial2: test} = require(\'ava\');',
-			errors
+			errors,
 		},
 		{
 			code: 'import test2 from \'ava\';',
-			errors
+			errors,
 		},
 		{
 			code: 'import {serial2} from \'ava\';',
-			errors
+			errors,
 		},
 		{
 			code: 'import {serial2 as test} from \'ava\';',
-			errors
-		}
-	]
+			errors,
+		},
+	],
 });
diff --git a/test/hooks-order.js b/test/hooks-order.js
index 8f2c112..3194827 100644
--- a/test/hooks-order.js
+++ b/test/hooks-order.js
@@ -5,8 +5,8 @@ const rule = require('../rules/hooks-order');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const errors = [{}];
@@ -123,7 +123,7 @@ ruleTester.run('no-todo-test', rule, {
 			test('foo', t => {
 				t.true(true);
 			});
-		`
+		`,
 	],
 	invalid: [
 		{
@@ -149,7 +149,7 @@ ruleTester.run('no-todo-test', rule, {
 					doFoo();
 				});
 			`,
-			errors
+			errors,
 		},
 		{
 			code: outdent`
@@ -182,7 +182,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 		{
 			code: outdent`
@@ -215,7 +215,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 		{
 			code: outdent`
@@ -240,7 +240,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 		{
 			code: outdent`
@@ -273,7 +273,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 		{
 			code: outdent`
@@ -306,7 +306,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 		{
 			code: outdent`
@@ -339,7 +339,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 		{
 			code: outdent`
@@ -364,7 +364,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 
 		{
@@ -398,7 +398,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 		{
 			code: outdent`
@@ -431,7 +431,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 		{
 			code: outdent`
@@ -464,7 +464,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 		{
 			code: outdent`
@@ -497,7 +497,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 		{
 			code: outdent`
@@ -522,7 +522,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 
 		{
@@ -556,7 +556,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 		{
 			code: outdent`
@@ -581,7 +581,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 
 		{
@@ -607,7 +607,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 
 		{
@@ -633,7 +633,7 @@ ruleTester.run('no-todo-test', rule, {
 					t.true(true);
 				});
 			`,
-			errors
+			errors,
 		},
 
 		{
@@ -663,7 +663,7 @@ ruleTester.run('no-todo-test', rule, {
 					doFoo();
 				});
 			`,
-			errors
+			errors,
 		},
 		{
 			code: outdent`
@@ -690,7 +690,7 @@ ruleTester.run('no-todo-test', rule, {
 					doFoo();
 				});
 			`,
-			errors
+			errors,
 		},
 		{
 			code: outdent`
@@ -717,7 +717,7 @@ ruleTester.run('no-todo-test', rule, {
 					doFoo();
 				});
 			`,
-			errors
-		}
-	]
+			errors,
+		},
+	],
 });
diff --git a/test/integration/eslint-config-ava-tester/index.js b/test/integration/eslint-config-ava-tester/index.js
index 3c4dbe6..72a4d2b 100644
--- a/test/integration/eslint-config-ava-tester/index.js
+++ b/test/integration/eslint-config-ava-tester/index.js
@@ -1,13 +1,12 @@
-'use strict';
 module.exports = {
-	parser: 'babel-eslint',
+	parser: '@babel/eslint-parser',
 	parserOptions: {
 		ecmaFeatures: {
-			jsx: true
-		}
+			jsx: true,
+		},
 	},
 	plugins: [
-		'ava'
+		'ava',
 	],
-	extends: 'plugin:ava/recommended'
+	extends: 'plugin:ava/recommended',
 };
diff --git a/test/integration/eslint-config-ava-tester/package.json b/test/integration/eslint-config-ava-tester/package.json
index 5d3c67e..ed36417 100644
--- a/test/integration/eslint-config-ava-tester/package.json
+++ b/test/integration/eslint-config-ava-tester/package.json
@@ -1,10 +1,11 @@
 {
     "name": "eslint-config-ava-tester",
     "dependencies": {
-        "@typescript-eslint/parser": "^2.34.0",
+        "@babel/eslint-parser": "^7.15.7",
+        "@typescript-eslint/parser": "^4.31.1",
         "babel-eslint": "^10.1.0",
-        "eslint": "^6.8.0",
+        "eslint": "^7.32.0",
         "eslint-plugin-ava": "file:../../..",
-        "typescript": "^3.9.9"
+        "typescript": "^4.4.3"
     }
 }
diff --git a/test/integration/test.js b/test/integration/test.js
index 2cf1d81..3dc19a9 100644
--- a/test/integration/test.js
+++ b/test/integration/test.js
@@ -1,6 +1,6 @@
 #!/usr/bin/env node
-'use strict';
 const path = require('path');
+const process = require('process');
 const Listr = require('listr');
 const tempy = require('tempy');
 const execa = require('execa');
@@ -39,7 +39,7 @@ const packages = new Map([
 	['p-queue', 'https://github.com/sindresorhus/p-queue'],
 	['pretty-bytes', 'https://github.com/sindresorhus/pretty-bytes'],
 	['normalize-url', 'https://github.com/sindresorhus/normalize-url'],
-	['pageres', 'https://github.com/sindresorhus/pageres']
+	['pageres', 'https://github.com/sindresorhus/pageres'],
 	// Disabled for now: https://github.com/avajs/eslint-plugin-ava/runs/2044891483?check_suite_focus=true
 	// ['got', 'https://github.com/sindresorhus/got']
 ]);
@@ -47,7 +47,7 @@ const packages = new Map([
 const typescriptPackages = new Set([
 	'pageres',
 	'got',
-	'p-queue'
+	'p-queue',
 ]);
 
 const cwd = path.join(__dirname, 'eslint-config-ava-tester');
@@ -114,32 +114,32 @@ const execute = name => {
 	return new Listr([
 		{
 			title: 'Cloning',
-			task: () => execa('git', ['clone', packages.get(name), '--single-branch', dest])
+			task: () => execa('git', ['clone', packages.get(name), '--single-branch', dest]),
 		},
 		{
 			title: 'Running eslint',
-			task: makeEslintTask(name, dest)
+			task: makeEslintTask(name, dest),
 		},
 		{
 			title: 'Running eslint --fix',
-			task: makeEslintTask(name, dest, ['--fix-dry-run'])
+			task: makeEslintTask(name, dest, ['--fix-dry-run']),
 		},
 		{
 			title: 'Clean up',
-			task: () => del(dest, {force: true})
-		}
+			task: () => del(dest, {force: true}),
+		},
 	].map(({title, task}) => ({
 		title: `${name} / ${title}`,
-		task
+		task,
 	})), {
-		exitOnError: false
+		exitOnError: false,
 	});
 };
 
 const list = new Listr([
 	{
 		title: 'Setup',
-		task: () => execa('npm', ['install', '../../..', 'eslint', 'babel-eslint', 'typescript', '@typescript-eslint/parser'], {cwd})
+		task: () => execa('npm', ['install', '../../..', 'eslint', 'babel-eslint', 'typescript', '@typescript-eslint/parser'], {cwd}),
 	},
 	{
 		title: 'Integration tests',
@@ -150,16 +150,16 @@ const list = new Listr([
 				tests.add([
 					{
 						title: name,
-						task: () => execute(name)
-					}
+						task: () => execute(name),
+					},
 				]);
 			}
 
 			return tests;
-		}
-	}
+		},
+	},
 ], {
-	renderer: process.env.INTEGRATION ? 'verbose' : 'default'
+	renderer: process.env.INTEGRATION ? 'verbose' : 'default',
 });
 
 list.run()
diff --git a/test/max-asserts.js b/test/max-asserts.js
index 17a59e5..3f91e37 100644
--- a/test/max-asserts.js
+++ b/test/max-asserts.js
@@ -4,8 +4,8 @@ const rule = require('../rules/max-asserts');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const errors = [{}];
@@ -24,57 +24,52 @@ ruleTester.run('max-asserts', rule, {
 		`,
 		`${header} test(t => { t.plan(5); ${nbAssertions(5)} });`,
 		`${header} test(t => { t.is.skip(1, 1); ${nbAssertions(4)} });`,
-		`${header} test.cb(t => { ${nbAssertions(5)} t.end(); });`,
 		{
 			code: `${header} test(t => { ${nbAssertions(3)} });`,
-			options: [3]
+			options: [3],
 		},
 		{
 			code: `${header} test(t => { notT.is(1, 1); notT.is(1, 1); notT.is(1, 1); });`,
-			options: [2]
+			options: [2],
 		},
 		`${header} test(t => { t.context.bar(); ${nbAssertions(5)} });`,
 		`${header} test(t => { ${'t.context.is(1, 1); '.repeat(6)}});`,
 		`${header} test(t => { ${'foo.t.is(1, 1); '.repeat(6)}});`,
 		// Shouldn't be triggered since it's not a test file
-		`test(t => { ${nbAssertions(10)} });`
+		`test(t => { ${nbAssertions(10)} });`,
 	],
 	invalid: [
 		{
 			code: `${header} test(t => { ${nbAssertions(6)} });`,
-			errors
+			errors,
 		},
 		{
 			code: `${header}
 				test(t => { ${nbAssertions(3)} });
 				test(t => { ${nbAssertions(6)} });
 			`,
-			errors
+			errors,
 		},
 		{
 			code: `${header} test(t => { t.plan(5); ${nbAssertions(6)} });`,
-			errors
+			errors,
 		},
 		{
 			code: `${header} test(t => { t.skip.is(1, 1); ${nbAssertions(5)} });`,
-			errors
-		},
-		{
-			code: `${header} test.cb(t => { ${nbAssertions(6)} t.end(); });`,
-			errors
+			errors,
 		},
 		{
 			code: `${header} test(t => { ${nbAssertions(4)} });`,
 			options: [3],
-			errors
+			errors,
 		},
 		{
 			code: `${header} test(t => { ${nbAssertions(10)} });`,
-			errors
+			errors,
 		},
 		{
 			code: `${header} test(t => { ${nbAssertions(10)} }); test(t => { ${nbAssertions(10)} });`,
-			errors: [...errors, ...errors] // Should have two errors, one per test
-		}
-	]
+			errors: [...errors, ...errors], // Should have two errors, one per test
+		},
+	],
 });
diff --git a/test/no-async-fn-without-await.js b/test/no-async-fn-without-await.js
index 26fee64..f62cd0d 100644
--- a/test/no-async-fn-without-await.js
+++ b/test/no-async-fn-without-await.js
@@ -8,9 +8,9 @@ const header = 'const test = require(\'ava\');\n';
 const ruleTesterOptions = [
 	{
 		parserOptions: {
-			ecmaVersion: 2021
-		}
-	}
+			ecmaVersion: 2021,
+		},
+	},
 	// Disabled for now because of `eslint-ava-rule-tester` problem
 	// {
 	// 	parser: require.resolve('babel-eslint'),
@@ -39,7 +39,7 @@ for (const options of ruleTesterOptions) {
 			`${header}test('title', function(t) {});`,
 			`${header}test('title', async t => { await foo(); });`,
 			// Shouldn't be triggered since it's not a test file
-			'test(async t => {});'
+			'test(async t => {});',
 		],
 		invalid: [
 			{
@@ -48,8 +48,8 @@ for (const options of ruleTesterOptions) {
 					message,
 					type: 'ArrowFunctionExpression',
 					line: 2,
-					column: 6
-				}]
+					column: 6,
+				}],
 			},
 			{
 				code: `${header}test(async function(t) {});`,
@@ -57,8 +57,8 @@ for (const options of ruleTesterOptions) {
 					message,
 					type: 'FunctionExpression',
 					line: 2,
-					column: 6
-				}]
+					column: 6,
+				}],
 			},
 			{
 				code: `${header}test(async t => {}); test(async t => {});`,
@@ -66,13 +66,13 @@ for (const options of ruleTesterOptions) {
 					message,
 					type: 'ArrowFunctionExpression',
 					line: 2,
-					column: 6
+					column: 6,
 				}, {
 					message,
 					type: 'ArrowFunctionExpression',
 					line: 2,
-					column: 27
-				}]
+					column: 27,
+				}],
 			},
 			{
 				code: `${header}test(async t => {}); test(async t => { await foo(); });`,
@@ -80,8 +80,8 @@ for (const options of ruleTesterOptions) {
 					message,
 					type: 'ArrowFunctionExpression',
 					line: 2,
-					column: 6
-				}]
+					column: 6,
+				}],
 			},
 			{
 				code: `${header}test(async t => { await foo(); }); test(async t => {});`,
@@ -89,8 +89,8 @@ for (const options of ruleTesterOptions) {
 					message,
 					type: 'ArrowFunctionExpression',
 					line: 2,
-					column: 41
-				}]
+					column: 41,
+				}],
 			},
 			{
 				code: `${header}test('title', async t => {});`,
@@ -98,9 +98,9 @@ for (const options of ruleTesterOptions) {
 					message,
 					type: 'ArrowFunctionExpression',
 					line: 2,
-					column: 15
-				}]
-			}
-		]
+					column: 15,
+				}],
+			},
+		],
 	});
 }
diff --git a/test/no-cb-test.js b/test/no-cb-test.js
deleted file mode 100644
index 9d572d1..0000000
--- a/test/no-cb-test.js
+++ /dev/null
@@ -1,51 +0,0 @@
-const test = require('ava');
-const avaRuleTester = require('eslint-ava-rule-tester');
-const rule = require('../rules/no-cb-test');
-
-const ruleTester = avaRuleTester(test, {
-	env: {
-		es6: true
-	}
-});
-
-const message = '`test.cb()` should not be used.';
-const header = 'const test = require(\'ava\');\n';
-
-ruleTester.run('no-cb-test', rule, {
-	valid: [
-		header + 'test("my test name", t => { t.pass(); });',
-		header + 'test.only("my test name", t => { t.pass(); });',
-		header + 'notTest.cb(t => { t.pass(); });',
-		// Shouldn't be triggered since it's not a test file
-		'test.cb(t => {});'
-	],
-	invalid: [
-		{
-			code: header + 'test.cb(t => { t.pass(); });',
-			errors: [{
-				message,
-				type: 'Identifier',
-				line: 2,
-				column: 6
-			}]
-		},
-		{
-			code: header + 'test.cb.skip(t => { t.pass(); t.end(); });',
-			errors: [{
-				message,
-				type: 'Identifier',
-				line: 2,
-				column: 6
-			}]
-		},
-		{
-			code: header + 'test.skip.cb(t => { t.pass(); t.end(); });',
-			errors: [{
-				message,
-				type: 'Identifier',
-				line: 2,
-				column: 11
-			}]
-		}
-	]
-});
diff --git a/test/no-duplicate-modifiers.js b/test/no-duplicate-modifiers.js
index a33e743..3110fd8 100644
--- a/test/no-duplicate-modifiers.js
+++ b/test/no-duplicate-modifiers.js
@@ -4,8 +4,8 @@ const rule = require('../rules/no-duplicate-modifiers');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const header = 'const test = require(\'ava\');\n';
@@ -16,12 +16,11 @@ const modifiers = [
 	'always',
 	'before',
 	'beforeEach',
-	'cb',
 	'failing',
 	'only',
 	'serial',
 	'skip',
-	'todo'
+	'todo',
 ];
 
 const valid = modifiers.map(modifier => `${header}test.${modifier}(t => {});`);
@@ -32,30 +31,17 @@ const invalid = modifiers.map(modifier => ({
 			message: `Duplicate test modifier \`.${modifier}\`.`,
 			type: 'Identifier',
 			line: 2,
-			column: 7 + modifier.length
-		}
-	]
+			column: 7 + modifier.length,
+		},
+	],
 }));
 
 ruleTester.run('no-duplicate-modifiers', rule, {
 	valid: [...valid,
 		`${header}test(t => {});`,
-		`${header}test.cb.only(t => {});`,
 		`${header}test.after.always(t => {});`,
 		`${header}test.afterEach.always(t => {});`,
-		`${header}test.failing.cb(t => {});`,
 		// Shouldn't be triggered since it's not a test file
 		'test.serial.serial(t => {});'],
-	invalid: [...invalid,
-		{
-			code: `${header}test.serial.cb.only.serial(t => {});`,
-			errors: [
-				{
-					message: 'Duplicate test modifier `.serial`.',
-					type: 'Identifier',
-					line: 2,
-					column: 21
-				}
-			]
-		}]
+	invalid,
 });
diff --git a/test/no-identical-title.js b/test/no-identical-title.js
index 5c339ba..3f6091c 100644
--- a/test/no-identical-title.js
+++ b/test/no-identical-title.js
@@ -4,8 +4,8 @@ const rule = require('../rules/no-identical-title');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const message = 'Test title is used multiple times in the same file.';
@@ -16,7 +16,6 @@ ruleTester.run('no-identical-title', rule, {
 	valid: [
 		header + 'test("my test name", t => {});',
 		header + 'test("a", t => {}); test("b", t => {});',
-		header + 'test("a", t => {}); test.cb("b", t => {});',
 		header + 'test.todo("a"); test.todo("b");',
 		header + 'test("a", t => {}); notTest("a", t => {});',
 		// eslint-disable-next-line no-template-curly-in-string
@@ -28,11 +27,11 @@ ruleTester.run('no-identical-title', rule, {
 		header + 'test.after(t => {}); test.after(t => {});',
 		header + 'test.beforeEach(t => {}); test.beforeEach(t => {});',
 		header + 'test.afterEach(t => {}); test.afterEach(t => {});',
-		header + 'test.cb.before(t => {}); test.before.cb(t => {});',
 		// Macros
 		` ${header}
 			const macro = (t, value) => { t.true(value); };
 
+			test(macro, true);
 			test('should work', macro, true);
 			test('should fail', macro, false);
 		`,
@@ -44,7 +43,7 @@ ruleTester.run('no-identical-title', rule, {
 		`,
 		// Shouldn't be triggered since it's not a test file
 		'test(t => {}); test(t => {});',
-		'test("a", t => {}); test("a", t => {});'
+		'test("a", t => {}); test("a", t => {});',
 	],
 	invalid: [
 		{
@@ -53,8 +52,8 @@ ruleTester.run('no-identical-title', rule, {
 				message,
 				type: 'Literal',
 				line: 2,
-				column: 26
-			}]
+				column: 26,
+			}],
 		},
 		{
 			code: header + 'test(`a`, t => {}); test(`a`, t => {});',
@@ -62,35 +61,8 @@ ruleTester.run('no-identical-title', rule, {
 				message,
 				type: 'TemplateLiteral',
 				line: 2,
-				column: 26
-			}]
-		},
-		{
-			code: header + 'test("a", t => {}); test.cb("a", t => {});',
-			errors: [{
-				message,
-				type: 'Literal',
-				line: 2,
-				column: 29
-			}]
-		},
-		{
-			code: header + 'test(`a`, t => {}); test.cb(`a`, t => {});',
-			errors: [{
-				message,
-				type: 'TemplateLiteral',
-				line: 2,
-				column: 29
-			}]
-		},
-		{
-			code: header + 'test("a", t => {}); test.cb.skip("a", t => {});',
-			errors: [{
-				message,
-				type: 'Literal',
-				line: 2,
-				column: 34
-			}]
+				column: 26,
+			}],
 		},
 		{
 			code: header + 'test("foo" + 1, t => {}); test("foo" + 1, t => {});',
@@ -98,8 +70,8 @@ ruleTester.run('no-identical-title', rule, {
 				message,
 				type: 'BinaryExpression',
 				line: 2,
-				column: 32
-			}]
+				column: 32,
+			}],
 		},
 		{
 			// eslint-disable-next-line no-template-curly-in-string
@@ -108,8 +80,8 @@ ruleTester.run('no-identical-title', rule, {
 				message,
 				type: 'TemplateLiteral',
 				line: 2,
-				column: 37
-			}]
+				column: 37,
+			}],
 		},
 		{
 			code: header + 'test.todo("a"); test.todo("a");',
@@ -117,8 +89,8 @@ ruleTester.run('no-identical-title', rule, {
 				message,
 				type: 'Literal',
 				line: 2,
-				column: 27
-			}]
-		}
-	]
+				column: 27,
+			}],
+		},
+	],
 });
diff --git a/test/no-ignored-test-files.js b/test/no-ignored-test-files.js
index caedbd0..5d2adbd 100644
--- a/test/no-ignored-test-files.js
+++ b/test/no-ignored-test-files.js
@@ -6,8 +6,8 @@ const rule = require('../rules/no-ignored-test-files');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const header = 'const test = require(\'ava\');\n';
@@ -28,36 +28,36 @@ util.loadAvaHelper = () => ({
 			default:
 				return {isHelper: false, isTest: false};
 		}
-	}
+	},
 });
 
 ruleTester.run('no-ignored-test-files', rule, {
 	valid: [
 		{
 			code: code(true),
-			filename: toPath('lib/foo.test.js')
-		}
+			filename: toPath('lib/foo.test.js'),
+		},
 	],
 	invalid: [
 		{
 			code: code(true),
 			filename: toPath('lib/foo/fixtures/bar.test.js'),
-			errors: [{message: 'AVA ignores this file.'}]
+			errors: [{message: 'AVA ignores this file.'}],
 		},
 		{
 			code: code(true),
 			filename: toPath('lib/foo/helpers/bar.test.js'),
-			errors: [{message: 'AVA treats this as a helper file.'}]
+			errors: [{message: 'AVA treats this as a helper file.'}],
 		},
 		{
 			code: code(true),
 			filename: toPath('test.js'),
-			errors: [{message: 'AVA ignores this file.'}]
+			errors: [{message: 'AVA ignores this file.'}],
 		},
 		{
 			code: code(true),
 			filename: toPath('bar/foo.test.js'),
-			errors: [{message: 'AVA ignores this file.'}]
-		}
-	]
+			errors: [{message: 'AVA ignores this file.'}],
+		},
+	],
 });
diff --git a/test/no-import-test-files.js b/test/no-import-test-files.js
index 80e70d9..150f52c 100644
--- a/test/no-import-test-files.js
+++ b/test/no-import-test-files.js
@@ -6,11 +6,11 @@ const rule = require('../rules/no-import-test-files');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
+		es6: true,
 	},
 	parserOptions: {
-		sourceType: 'module'
-	}
+		sourceType: 'module',
+	},
 });
 
 const rootDir = path.dirname(__dirname);
@@ -28,13 +28,13 @@ util.loadAvaHelper = () => ({
 			default:
 				return {isHelper: false, isTest: false};
 		}
-	}
+	},
 });
 
 const errors = [
 	{
-		message: 'Test files should not be imported.'
-	}
+		message: 'Test files should not be imported.',
+	},
 ];
 
 ruleTester.run('no-import-test-files', rule, {
@@ -48,21 +48,21 @@ ruleTester.run('no-import-test-files', rule, {
 		'const highlight = require(\'highlight.js\')',
 		{
 			code: 'const highlight = require(\'highlight.js\')',
-			filename: toPath('test/index.js')
+			filename: toPath('test/index.js'),
 		},
 		'const value = require(true);',
-		'const value = require();'
+		'const value = require();',
 	],
 	invalid: [
 		{
 			code: 'const test = require(\'./foo.test.js\');',
 			filename: toPath('lib/foo.js'),
-			errors
+			errors,
 		},
 		{
 			code: 'const test = require(\'../foo.test.js\');',
 			filename: toPath('foo.js'),
-			errors
-		}
-	]
+			errors,
+		},
+	],
 });
diff --git a/test/no-incorrect-deep-equal.js b/test/no-incorrect-deep-equal.js
index 4f4d6b5..80aa34f 100644
--- a/test/no-incorrect-deep-equal.js
+++ b/test/no-incorrect-deep-equal.js
@@ -4,12 +4,12 @@ const rule = require('../rules/no-incorrect-deep-equal');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const error = {
-	messageId: 'no-deep-equal-with-primative'
+	messageId: 'no-deep-equal-with-primative',
 };
 
 const header = 'const test = require(\'ava\');\n';
@@ -51,7 +51,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 			test('x', t => {
 				t.deepEqual(/regex/, expression);
 			});
-		`
+		`,
 	],
 	invalid: [
 		{
@@ -67,7 +67,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.is(expression, 'foo');
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -82,7 +82,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.is('foo', expression);
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -97,7 +97,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.not(expression, 'foo');
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -112,7 +112,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.not('foo', expression);
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -127,7 +127,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.is(expression, 1);
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -142,7 +142,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.is(expression, \`foo\${bar}\`);
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -157,7 +157,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.is(\`foo\${bar}\`, expression);
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -172,7 +172,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.not(expression, \`foo\${bar}\`);
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -187,7 +187,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.not(\`foo\${bar}\`, expression);
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -202,7 +202,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.is(expression, null);
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -217,7 +217,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.is(null, expression);
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -232,7 +232,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.not(expression, null);
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -247,7 +247,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.not(null, expression);
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -262,7 +262,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.is(expression, undefined);
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -277,7 +277,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.is(undefined, expression);
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -292,7 +292,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.not(expression, undefined);
 				});
 			`,
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: `
@@ -307,7 +307,7 @@ ruleTester.run('no-incorrect-deep-equal', rule, {
 					t.not(undefined, expression);
 				});
 			`,
-			errors: [error]
-		}
-	]
+			errors: [error],
+		},
+	],
 });
diff --git a/test/no-inline-assertions.js b/test/no-inline-assertions.js
index 2d20e1b..aeeb3f4 100644
--- a/test/no-inline-assertions.js
+++ b/test/no-inline-assertions.js
@@ -4,8 +4,8 @@ const rule = require('../rules/no-inline-assertions');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const errors = [{}];
@@ -25,23 +25,23 @@ ruleTester.run('no-todo-test', rule, {
 		'test.todo("my test name");',
 		// Shouldn't be triggered since the signature is incorrect
 		header + 'test.todo("my test name", "bar");',
-		header + 'test.todo("my test name", undefined, t => {})'
+		header + 'test.todo("my test name", undefined, t => {})',
 	],
 	invalid: [
 		{
 			code: header + 'test("my test name", t => t.skip());',
 			errors,
-			output: header + 'test("my test name", t => {t.skip()});'
+			output: header + 'test("my test name", t => {t.skip()});',
 		},
 		{
 			code: header + 'test("my test name", t => t.true(fn()));',
 			errors,
-			output: header + 'test("my test name", t => {t.true(fn())});'
+			output: header + 'test("my test name", t => {t.true(fn())});',
 		},
 		{
 			code: header + 'test("my test name", t => \n t.true(fn()));',
 			errors,
-			output: header + 'test("my test name", t => \n {t.true(fn())});'
-		}
-	]
+			output: header + 'test("my test name", t => \n {t.true(fn())});',
+		},
+	],
 });
diff --git a/test/no-invalid-end.js b/test/no-invalid-end.js
deleted file mode 100644
index 4df67f4..0000000
--- a/test/no-invalid-end.js
+++ /dev/null
@@ -1,42 +0,0 @@
-const test = require('ava');
-const avaRuleTester = require('eslint-ava-rule-tester');
-const rule = require('../rules/no-invalid-end');
-
-const ruleTester = avaRuleTester(test, {
-	env: {
-		es6: true
-	}
-});
-
-const errors = [{}];
-const header = 'const test = require(\'ava\');\n';
-
-ruleTester.run('no-invalid-end', rule, {
-	valid: [
-		header + 'test(t => {});',
-		header + 'test(t => { t.is(1, 1); });',
-		header + 'test.only(t => {});',
-		header + 'test.cb(t => { t.end(); });',
-		header + 'test.cb(t => { t.end.skip(); });',
-		header + 'test.cb.only(t => { t.end(); });',
-		header + 'notTest(t => { t.end(); });',
-		header + 'test(t => { t.context.end(); })',
-		header + 'test(t => { foo.t.end(); })',
-		// Shouldn't be triggered since it's not a test file
-		'test(t => { t.end(); });'
-	],
-	invalid: [
-		{
-			code: header + 'test(t => { t.end(); });',
-			errors
-		},
-		{
-			code: header + 'test.only(t => { t.end(); });',
-			errors
-		},
-		{
-			code: header + 'test(t => { t.end.skip(); });',
-			errors
-		}
-	]
-});
diff --git a/test/no-nested-tests.js b/test/no-nested-tests.js
index 579d8ba..79d202f 100644
--- a/test/no-nested-tests.js
+++ b/test/no-nested-tests.js
@@ -4,13 +4,13 @@ const rule = require('../rules/no-nested-tests');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const header = 'const test = require(\'ava\');\n';
 const error = {
-	message: 'Tests should not be nested.'
+	message: 'Tests should not be nested.',
 };
 
 ruleTester.run('no-nested-tests', rule, {
@@ -24,20 +24,20 @@ ruleTester.run('no-nested-tests', rule, {
 		header + 'test.only(t => {});',
 		header + 'test.only(t => {}); test.only(t => {});',
 		// Shouldn't be triggered since it's not a test file
-		'test(t => { test(t => {}); });'
+		'test(t => { test(t => {}); });',
 	],
 	invalid: [
 		{
 			code: header + 'test("2", t => { test(t => {}); });',
-			errors: [error]
+			errors: [error],
 		},
 		{
 			code: header + 'test(t => { test(t => {}); test(t => {}); });',
-			errors: [error, error]
+			errors: [error, error],
 		},
 		{
 			code: header + 'test(t => { test(t => { test(t => {}); }); });',
-			errors: [error, error]
-		}
-	]
+			errors: [error, error],
+		},
+	],
 });
diff --git a/test/no-only-test.js b/test/no-only-test.js
index cecf9d3..bcca949 100644
--- a/test/no-only-test.js
+++ b/test/no-only-test.js
@@ -4,11 +4,11 @@ const rule = require('../rules/no-only-test');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
+		es6: true,
 	},
 	parserOptions: {
-		sourceType: 'module'
-	}
+		sourceType: 'module',
+	},
 });
 
 const message = '`test.only()` should not be used.';
@@ -17,11 +17,10 @@ const header = 'const test = require(\'ava\');\n';
 ruleTester.run('no-only-test', rule, {
 	valid: [
 		header + 'test("my test name", t => { t.pass(); });',
-		header + 'test.cb("my test name", t => { t.pass(); t.end(); });',
 		header + 'test(t => { t.pass(); }); test(t => { t.pass(); });',
 		header + 'notTest.only();',
 		// Shouldn't be triggered since it's not a test file
-		'test.only(t => {});'
+		'test.only(t => {});',
 	],
 	invalid: [
 		{
@@ -33,9 +32,9 @@ ruleTester.run('no-only-test', rule, {
 				column: 3,
 				suggestions: [{
 					desc: 'Remove the `.only`',
-					output: header + 'test\n\t(t => { t.pass(); });'
-				}]
-			}]
+					output: header + 'test\n\t(t => { t.pass(); });',
+				}],
+			}],
 		},
 		{
 			code: header + 'test\n  .only(t => { t.pass(); });',
@@ -46,9 +45,9 @@ ruleTester.run('no-only-test', rule, {
 				column: 4,
 				suggestions: [{
 					desc: 'Remove the `.only`',
-					output: header + 'test\n  (t => { t.pass(); });'
-				}]
-			}]
+					output: header + 'test\n  (t => { t.pass(); });',
+				}],
+			}],
 		},
 		{
 			code: header + 'test\t.only(t => { t.pass(); });',
@@ -59,9 +58,9 @@ ruleTester.run('no-only-test', rule, {
 				column: 7,
 				suggestions: [{
 					desc: 'Remove the `.only`',
-					output: header + 'test\t(t => { t.pass(); });'
-				}]
-			}]
+					output: header + 'test\t(t => { t.pass(); });',
+				}],
+			}],
 		},
 		{
 			code: header + 'test  .only(t => { t.pass(); });',
@@ -72,9 +71,9 @@ ruleTester.run('no-only-test', rule, {
 				column: 8,
 				suggestions: [{
 					desc: 'Remove the `.only`',
-					output: header + 'test  (t => { t.pass(); });'
-				}]
-			}]
+					output: header + 'test  (t => { t.pass(); });',
+				}],
+			}],
 		},
 		{
 			code: header + 'test.\n\tonly(t => { t.pass(); });',
@@ -85,9 +84,9 @@ ruleTester.run('no-only-test', rule, {
 				column: 2,
 				suggestions: [{
 					desc: 'Remove the `.only`',
-					output: header + 'test\n\t(t => { t.pass(); });'
-				}]
-			}]
+					output: header + 'test\n\t(t => { t.pass(); });',
+				}],
+			}],
 		},
 		{
 			code: header + 'test.\n  only(t => { t.pass(); });',
@@ -98,9 +97,9 @@ ruleTester.run('no-only-test', rule, {
 				column: 3,
 				suggestions: [{
 					desc: 'Remove the `.only`',
-					output: header + 'test\n  (t => { t.pass(); });'
-				}]
-			}]
+					output: header + 'test\n  (t => { t.pass(); });',
+				}],
+			}],
 		},
 		{
 			code: header + 'test.only(t => { t.pass(); });',
@@ -111,35 +110,9 @@ ruleTester.run('no-only-test', rule, {
 				column: 6,
 				suggestions: [{
 					desc: 'Remove the `.only`',
-					output: header + 'test(t => { t.pass(); });'
-				}]
-			}]
-		},
-		{
-			code: header + 'test.cb.only(t => { t.pass(); t.end(); });',
-			errors: [{
-				message,
-				type: 'Identifier',
-				line: 2,
-				column: 9,
-				suggestions: [{
-					desc: 'Remove the `.only`',
-					output: header + 'test.cb(t => { t.pass(); t.end(); });'
-				}]
-			}]
+					output: header + 'test(t => { t.pass(); });',
+				}],
+			}],
 		},
-		{
-			code: header + 'test.only.cb(t => { t.pass(); t.end(); });',
-			errors: [{
-				message,
-				type: 'Identifier',
-				line: 2,
-				column: 6,
-				suggestions: [{
-					desc: 'Remove the `.only`',
-					output: header + 'test.cb(t => { t.pass(); t.end(); });'
-				}]
-			}]
-		}
-	]
+	],
 });
diff --git a/test/no-skip-assert.js b/test/no-skip-assert.js
index 48d4105..9f3834e 100644
--- a/test/no-skip-assert.js
+++ b/test/no-skip-assert.js
@@ -4,8 +4,8 @@ const rule = require('../rules/no-skip-assert');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const errors = [{}];
@@ -21,24 +21,20 @@ ruleTester.run('no-skip-assert', rule, {
 		header + 'test(t => { foo.t.is.skip(1, 1); });',
 		header + 'test(t => { t.skip(); });',
 		// Shouldn't be triggered since it's not a test file
-		'test(t => { t.is.skip(1, 1); });'
+		'test(t => { t.is.skip(1, 1); });',
 	],
 	invalid: [
 		{
 			code: header + 'test(t => { t.is.skip(1, 1); });',
-			errors
+			errors,
 		},
 		{
 			code: header + 'test(t => { t.true.skip(1); });',
-			errors
-		},
-		{
-			code: header + 'test.cb(t => { t.is.skip(1, 1); t.end(); });',
-			errors
+			errors,
 		},
 		{
 			code: header + 'test.skip(t => { t.is.skip(1, 1); });',
-			errors
-		}
-	]
+			errors,
+		},
+	],
 });
diff --git a/test/no-skip-test.js b/test/no-skip-test.js
index cd6e60a..636a3dd 100644
--- a/test/no-skip-test.js
+++ b/test/no-skip-test.js
@@ -4,8 +4,8 @@ const rule = require('../rules/no-skip-test');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const message = 'No tests should be skipped.';
@@ -14,12 +14,11 @@ const header = 'const test = require(\'ava\');\n';
 ruleTester.run('no-skip-test', rule, {
 	valid: [
 		header + 'test("my test name", t => { t.pass(); });',
-		header + 'test.cb("my test name", t => { t.pass(); t.end(); });',
 		header + 'test(t => { t.pass(); }); test(t => { t.pass(); });',
 		header + 'test(t => { t.skip.is(1, 2); });',
 		header + 'notTest.skip();',
 		// Shouldn't be triggered since it's not a test file
-		'test.skip(t => {});'
+		'test.skip(t => {});',
 	],
 	invalid: [
 		{
@@ -31,61 +30,9 @@ ruleTester.run('no-skip-test', rule, {
 				column: 6,
 				suggestions: [{
 					desc: 'Remove the `.skip`',
-					output: header + 'test(t => { t.pass(); });'
-				}]
-			}]
+					output: header + 'test(t => { t.pass(); });',
+				}],
+			}],
 		},
-		{
-			code: header + 'test.cb.skip(t => { t.pass(); t.end(); });',
-			errors: [{
-				message,
-				type: 'Identifier',
-				line: 2,
-				column: 9,
-				suggestions: [{
-					desc: 'Remove the `.skip`',
-					output: header + 'test.cb(t => { t.pass(); t.end(); });'
-				}]
-			}]
-		},
-		{
-			code: header + 'test.skip.cb(t => { t.pass(); t.end(); });',
-			errors: [{
-				message,
-				type: 'Identifier',
-				line: 2,
-				column: 6,
-				suggestions: [{
-					desc: 'Remove the `.skip`',
-					output: header + 'test.cb(t => { t.pass(); t.end(); });'
-				}]
-			}]
-		},
-		{
-			code: header + 'test.\n\tskip.cb(t => { t.pass(); t.end(); });',
-			errors: [{
-				message,
-				type: 'Identifier',
-				line: 3,
-				column: 2,
-				suggestions: [{
-					desc: 'Remove the `.skip`',
-					output: header + 'test\n\t.cb(t => { t.pass(); t.end(); });'
-				}]
-			}]
-		},
-		{
-			code: header + 'test  .skip  .cb(t => { t.pass(); t.end(); });',
-			errors: [{
-				message,
-				type: 'Identifier',
-				line: 2,
-				column: 8,
-				suggestions: [{
-					desc: 'Remove the `.skip`',
-					output: header + 'test    .cb(t => { t.pass(); t.end(); });'
-				}]
-			}]
-		}
-	]
+	],
 });
diff --git a/test/no-statement-after-end.js b/test/no-statement-after-end.js
deleted file mode 100644
index 2aef50f..0000000
--- a/test/no-statement-after-end.js
+++ /dev/null
@@ -1,82 +0,0 @@
-const test = require('ava');
-const avaRuleTester = require('eslint-ava-rule-tester');
-const rule = require('../rules/no-statement-after-end');
-
-const ruleTester = avaRuleTester(test, {
-	env: {
-		es6: true
-	}
-});
-
-const errors = [{}];
-const header = 'const test = require(\'ava\');\n';
-
-function cbTest(contents, prependHeader) {
-	let returnValue = `test.cb(t => { ${contents} });`;
-
-	if (prependHeader !== false) {
-		returnValue = header + returnValue;
-	}
-
-	return returnValue;
-}
-
-ruleTester.run('no-statement-after-end', rule, {
-	valid: [
-		cbTest('t.end();'),
-		cbTest('t.is(1, 1); t.end();'),
-		cbTest('notT.end(); t.is(1, 1);'),
-		cbTest('if (t.context.a === 1) { return t.end(); } \n t.is(1, 1); t.end();'),
-		cbTest('return t.end();'),
-		cbTest('t.end(); return;'),
-		// Valid because it is not a test file (no header)
-		cbTest('t.end(); t.is(1, 1);', false),
-		`
-		const test = require('ava');
-
-		throw new Error();
-
-		1;
-		`,
-		cbTest(`
-			function newCodePath() {
-				throw new Error('make some unreachable code');
-				t.end();
-			}
-
-			1;
-		`)
-	],
-	invalid: [
-		{
-			code: cbTest('t.end(); t.is(1, 1);'),
-			errors
-		},
-		{
-			code: cbTest('t.end(); return 3 + 4;'),
-			errors
-		},
-		{
-			code: cbTest('t.end(); console.log("end");'),
-			errors
-		},
-		{
-			code: cbTest('if (t.context.a === 1) { t.end(); }\nt.is(1, 1); t.end();'),
-			errors
-		},
-		{
-			code: cbTest(`
-				function newCodePath() {
-					// ...
-				}
-				t.end();
-				1;
-			`),
-			errors
-		},
-		{
-			code: cbTest('t.end(); function newCodePath() {} 1;'),
-			errors
-		}
-	]
-});
diff --git a/test/no-todo-implementation.js b/test/no-todo-implementation.js
index 1c0e289..6761d7c 100644
--- a/test/no-todo-implementation.js
+++ b/test/no-todo-implementation.js
@@ -4,12 +4,12 @@ const rule = require('../rules/no-todo-implementation');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const errors = [{
-	message: '`test.todo()` should not be passed an implementation function.'
+	message: '`test.todo()` should not be passed an implementation function.',
 }];
 const header = 'const test = require(\'ava\');\n';
 
@@ -18,51 +18,34 @@ ruleTester.run('no-todo-implementation', rule, {
 		header + 'test(t => {});',
 		header + 'test("title", t => {});',
 		header + 'test.todo("title");',
-		header + 'test.todo.cb("title");',
 		header + 'notTest.todo(t => {});',
 		// Shouldn't be triggered since it's not a test file
-		'test.todo("title", t => {});'
+		'test.todo("title", t => {});',
 	],
 	invalid: [
 		{
 			code: header + 'test.todo("title", t => {});',
-			errors
+			errors,
 		},
 		{
 			code: header + 'test.todo(t => {});',
-			errors
+			errors,
 		},
 		{
 			code: header + 'test.todo("title", function (t) {});',
-			errors
+			errors,
 		},
 		{
 			code: header + 'test.todo(function (t) {});',
-			errors
+			errors,
 		},
 		{
 			code: header + 'test.todo("title", function foo(t) {});',
-			errors
+			errors,
 		},
 		{
 			code: header + 'test.todo(function foo(t) {});',
-			errors
+			errors,
 		},
-		{
-			code: header + 'test.todo.cb("title", t => {});',
-			errors
-		},
-		{
-			code: header + 'test.todo.cb(t => {});',
-			errors
-		},
-		{
-			code: header + 'test.cb.todo("title", t => {});',
-			errors
-		},
-		{
-			code: header + 'test.cb.todo(t => {});',
-			errors
-		}
-	]
+	],
 });
diff --git a/test/no-todo-test.js b/test/no-todo-test.js
index 100544e..640586f 100644
--- a/test/no-todo-test.js
+++ b/test/no-todo-test.js
@@ -4,8 +4,8 @@ const rule = require('../rules/no-todo-test');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const errors = [{}];
@@ -17,20 +17,12 @@ ruleTester.run('no-todo-test', rule, {
 		header + 'test.only("my test name", t => { t.pass(); });',
 		header + 'notTest.todo(t => { t.pass(); });',
 		// Shouldn't be triggered since it's not a test file
-		'test.todo("my test name");'
+		'test.todo("my test name");',
 	],
 	invalid: [
 		{
 			code: header + 'test.todo("my test name");',
-			errors
+			errors,
 		},
-		{
-			code: header + 'test.todo.cb("my test name");',
-			errors
-		},
-		{
-			code: header + 'test.cb.todo("my test name");',
-			errors
-		}
-	]
+	],
 });
diff --git a/test/no-unknown-modifiers.js b/test/no-unknown-modifiers.js
index 0351aed..b3ab236 100644
--- a/test/no-unknown-modifiers.js
+++ b/test/no-unknown-modifiers.js
@@ -4,8 +4,8 @@ const rule = require('../rules/no-unknown-modifiers');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const header = 'const test = require(\'ava\');\n';
@@ -17,8 +17,8 @@ ruleTester.run('no-unknown-modifiers', rule, {
 		`${header}test.afterEach(t => {});`,
 		`${header}test.before(t => {});`,
 		`${header}test.beforeEach(t => {});`,
-		`${header}test.cb(t => {});`,
-		`${header}test.cb.only(t => {});`,
+		`${header}test.default(t => {});`,
+		`${header}test.default.serial(t => {});`,
 		`${header}test.only(t => {});`,
 		`${header}test.serial(t => {});`,
 		`${header}test.skip(t => {});`,
@@ -26,8 +26,9 @@ ruleTester.run('no-unknown-modifiers', rule, {
 		`${header}test.after.always(t => {});`,
 		`${header}test.afterEach.always(t => {});`,
 		`${header}test.failing(t => {});`,
+		`${header}test.macro(t => {});`,
 		// Shouldn't be triggered since it's not a test file
-		'test.foo(t => {});'
+		'test.foo(t => {});',
 	],
 	invalid: [
 		{
@@ -36,8 +37,8 @@ ruleTester.run('no-unknown-modifiers', rule, {
 				message: 'Unknown test modifier `.foo`.',
 				type: 'Identifier',
 				line: 2,
-				column: 6
-			}]
+				column: 6,
+			}],
 		},
 		{
 			code: `${header}test.onlu(t => {});`,
@@ -45,8 +46,8 @@ ruleTester.run('no-unknown-modifiers', rule, {
 				message: 'Unknown test modifier `.onlu`.',
 				type: 'Identifier',
 				line: 2,
-				column: 6
-			}]
+				column: 6,
+			}],
 		},
 		{
 			code: `${header}test.beforeeach(t => {});`,
@@ -54,8 +55,8 @@ ruleTester.run('no-unknown-modifiers', rule, {
 				message: 'Unknown test modifier `.beforeeach`.',
 				type: 'Identifier',
 				line: 2,
-				column: 6
-			}]
+				column: 6,
+			}],
 		},
 		{
 			code: `${header}test.c.only(t => {});`,
@@ -63,17 +64,17 @@ ruleTester.run('no-unknown-modifiers', rule, {
 				message: 'Unknown test modifier `.c`.',
 				type: 'Identifier',
 				line: 2,
-				column: 6
-			}]
+				column: 6,
+			}],
 		},
 		{
-			code: `${header}test.cb.onlu(t => {});`,
+			code: `${header}test.cb(t => {});`,
 			errors: [{
-				message: 'Unknown test modifier `.onlu`.',
+				message: 'Unknown test modifier `.cb`.',
 				type: 'Identifier',
 				line: 2,
-				column: 9
-			}]
+				column: 6,
+			}],
 		},
 		{
 			code: `${header}test.foo.bar.baz(t => {});`,
@@ -81,17 +82,8 @@ ruleTester.run('no-unknown-modifiers', rule, {
 				message: 'Unknown test modifier `.foo`.',
 				type: 'Identifier',
 				line: 2,
-				column: 6
-			}]
-		},
-		{
-			code: `${header}test.default(t => {});`,
-			errors: [{
-				message: 'Unknown test modifier `.default`.',
-				type: 'Identifier',
-				line: 2,
-				column: 6
-			}]
+				column: 6,
+			}],
 		},
 		{
 			code: `${header}test.test(t => {});`,
@@ -99,8 +91,8 @@ ruleTester.run('no-unknown-modifiers', rule, {
 				message: 'Unknown test modifier `.test`.',
 				type: 'Identifier',
 				line: 2,
-				column: 6
-			}]
-		}
-	]
+				column: 6,
+			}],
+		},
+	],
 });
diff --git a/test/package.js b/test/package.js
index 78c7ef6..24520ee 100644
--- a/test/package.js
+++ b/test/package.js
@@ -12,7 +12,7 @@ test.before(async () => {
 });
 
 const testSorted = (t, actualOrder, sourceName) => {
-	const sortedOrder = actualOrder.slice(0).sort();
+	const sortedOrder = [...actualOrder].sort();
 
 	for (const [wantedIndex, name] of sortedOrder.entries()) {
 		const actualIndex = actualOrder.indexOf(name);
diff --git a/test/prefer-async-await.js b/test/prefer-async-await.js
index 2187476..9d1eb73 100644
--- a/test/prefer-async-await.js
+++ b/test/prefer-async-await.js
@@ -4,13 +4,13 @@ const rule = require('../rules/prefer-async-await');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const header = 'const test = require(\'ava\');\n';
 const errors = [{
-	message: 'Prefer using async/await instead of returning a Promise.'
+	message: 'Prefer using async/await instead of returning a Promise.',
 }];
 
 ruleTester.run('prefer-async-await', rule, {
@@ -24,28 +24,28 @@ ruleTester.run('prefer-async-await', rule, {
 		// TODO: this should be an error, needs improvement
 		header + 'test(t => { const bar = foo().then(fn); return bar; });',
 		// Shouldn't be triggered since it's not a test file
-		'test(t => { return foo().then(fn); });'
+		'test(t => { return foo().then(fn); });',
 	],
 	invalid: [
 		{
 			code: header + 'test(t => { return foo().then(fn); });',
-			errors
+			errors,
 		},
 		{
 			code: header + 'test(function(t) { return foo().then(fn); });',
-			errors
+			errors,
 		},
 		{
 			code: header + 'test(t => { return foo().then(fn).catch(fn2); });',
-			errors
+			errors,
 		},
 		{
 			code: header + 'test(t => { return foo().catch(fn2).then(fn); });',
-			errors
+			errors,
 		},
 		{
 			code: header + 'test(t => { const bar = foo(); return bar.then(fn); });',
-			errors
-		}
-	]
+			errors,
+		},
+	],
 });
diff --git a/test/prefer-power-assert.js b/test/prefer-power-assert.js
index 55c5baa..0f9a4da 100644
--- a/test/prefer-power-assert.js
+++ b/test/prefer-power-assert.js
@@ -4,12 +4,12 @@ const rule = require('../rules/prefer-power-assert');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
+		es6: true,
 	},
 	parserOptions: {
 		ecmaVersion: 2021,
-		sourceType: 'module'
-	}
+		sourceType: 'module',
+	},
 });
 
 const errors = [{}];
@@ -20,13 +20,13 @@ function testNotAllowedMethod(methodName) {
 		invalid: [
 			{
 				code: `import test from 'ava';\n test(t => { t.${methodName}; });`,
-				errors
+				errors,
 			},
 			{
 				code: `import test from 'ava';\n test(t => { t.skip.${methodName}; });`,
-				errors
-			}
-		]
+				errors,
+			},
+		],
 	});
 }
 
@@ -39,7 +39,7 @@ const notAllowedMethods = [
 	'not(foo, bar)',
 	'regex(str, re)',
 	'notRegex(str, re)',
-	'ifError(err)'
+	'ifError(err)',
 ];
 
 for (const methodName of notAllowedMethods) {
@@ -50,13 +50,13 @@ function testAllowedMethod(methodName) {
 	ruleTester.run('prefer-power-assert', rule, {
 		valid: [
 			{
-				code: `import test from 'ava';\n test(t => { t.${methodName}; });`
+				code: `import test from 'ava';\n test(t => { t.${methodName}; });`,
 			},
 			{
-				code: `import test from 'ava';\n test(t => { t.skip.${methodName}; });`
-			}
+				code: `import test from 'ava';\n test(t => { t.skip.${methodName}; });`,
+			},
 		],
-		invalid: []
+		invalid: [],
 	});
 }
 
@@ -68,7 +68,7 @@ const allowedMethods = [
 	'throws(block)',
 	'notThrows(block)',
 	'pass(foo)',
-	'fail(foo)'
+	'fail(foo)',
 ];
 
 for (const methodName of allowedMethods) {
@@ -79,19 +79,19 @@ function testWithModifier(modifier) {
 	ruleTester.run('prefer-power-assert', rule, {
 		valid: [
 			{
-				code: `import test from 'ava';\n test.${modifier}(t => { t.assert(foo); });`
-			}
+				code: `import test from 'ava';\n test.${modifier}(t => { t.assert(foo); });`,
+			},
 		],
 		invalid: [
 			{
 				code: `import test from 'ava';\n test.${modifier}(t => { t.is(foo); });`,
-				errors
-			}
-		]
+				errors,
+			},
+		],
 	});
 }
 
-for (const modifiers of ['skip', 'only', 'cb', 'serial']) {
+for (const modifiers of ['skip', 'only', 'serial']) {
 	testWithModifier(modifiers);
 }
 
@@ -99,15 +99,15 @@ function testDeclaration(declaration) {
 	ruleTester.run('prefer-power-assert', rule, {
 		valid: [
 			{
-				code: `${declaration}\n test(t => { t.assert(foo); });`
-			}
+				code: `${declaration}\n test(t => { t.assert(foo); });`,
+			},
 		],
 		invalid: [
 			{
 				code: `${declaration}\n test(t => { t.is(foo); });`,
-				errors
-			}
-		]
+				errors,
+			},
+		],
 	});
 }
 
@@ -115,7 +115,7 @@ for (const declaration of [
 	'var test = require(\'ava\');',
 	'let test = require(\'ava\');',
 	'const test = require(\'ava\');',
-	'import test from \'ava\';'
+	'import test from \'ava\';',
 ]) {
 	testDeclaration(declaration);
 }
@@ -134,17 +134,17 @@ test(t => {
 ruleTester.run('prefer-power-assert', rule, {
 	valid: [
 		{
-			code: 'import test from \'ava\';\n test.cb(function (t) { t.assert(foo); t.end(); });'
+			code: 'import test from \'ava\';\n test(function (t) { t.assert(foo); });',
 		},
 		// Shouldn't be triggered since it's not a test file
 		{
-			code: 'test(t => {});'
-		}
+			code: 'test(t => {});',
+		},
 	],
 	invalid: [
 		{
 			code: assertionInNestedCode,
-			errors
-		}
-	]
+			errors,
+		},
+	],
 });
diff --git a/test/prefer-t-regex.js b/test/prefer-t-regex.js
index 7eb917e..1e96ae6 100644
--- a/test/prefer-t-regex.js
+++ b/test/prefer-t-regex.js
@@ -4,12 +4,12 @@ const rule = require('../rules/prefer-t-regex');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const errors = assertion => [{
-	message: `Prefer using the \`t.${assertion}()\` assertion.`
+	message: `Prefer using the \`t.${assertion}()\` assertion.`,
 }];
 const header = 'const test = require(\'ava\');\n';
 
@@ -33,145 +33,145 @@ ruleTester.run('prefer-t-regex', rule, {
 		header + 'test(t => t.regex(foo, new RegExp(/\\d+/)));',
 		header + 'test(t => t.regex(foo, RegExp(/\\d+/)));',
 		// Shouldn't be triggered since it's not a test file
-		'test(t => t.true(/\\d+/.test("foo")));'
+		'test(t => t.true(/\\d+/.test("foo")));',
 	],
 	invalid: [
 		{
 			code: header + 'test(t => t.true(/\\d+/.test("foo")));',
 			output: header + 'test(t => t.regex("foo", /\\d+/));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		{
 			code: header + 'test(t => t.false(foo.search(/\\d+/)));',
 			output: header + 'test(t => t.notRegex(foo, /\\d+/));',
-			errors: errors('notRegex')
+			errors: errors('notRegex'),
 		},
 		{
 			code: header + 'const regexp = /\\d+/;\ntest(t => t.true(foo.search(regexp)));',
 			output: header + 'const regexp = /\\d+/;\ntest(t => t.regex(foo, regexp));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		{
 			code: header + 'test(t => t.truthy(foo.match(/\\d+/)));',
 			output: header + 'test(t => t.regex(foo, /\\d+/));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		{
 			code: header + 'test(t => t.false(/\\d+/.test("foo")));',
 			output: header + 'test(t => t.notRegex("foo", /\\d+/));',
-			errors: errors('notRegex')
+			errors: errors('notRegex'),
 		},
 		{
 			code: header + 'test(t => t.true(/\\d+/.test(foo())));',
 			output: header + 'test(t => t.regex(foo(), /\\d+/));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		{
 			code: header + 'test(t => t.is(/\\d+/.test(foo), true));',
 			output: header + 'test(t => t.regex(foo, /\\d+/));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		{
 			code: header + 'test(t => t.is(/\\d+/.test(foo), false));',
 			output: header + 'test(t => t.notRegex(foo, /\\d+/));',
-			errors: errors('notRegex')
+			errors: errors('notRegex'),
 		},
 		{
 			code: header + 'const reg = /\\d+/;\ntest(t => t.true(reg.test(foo.bar())));',
 			output: header + 'const reg = /\\d+/;\ntest(t => t.regex(foo.bar(), reg));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		// The same as the above tests but with `RegExp()` object instead of a regex literal
 		{
 			code: header + 'test(t => t.true(new RegExp("\\d+").test("foo")));',
 			output: header + 'test(t => t.regex("foo", new RegExp("\\d+")));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		{
 			code: header + 'test(t => t.false(foo.search(new RegExp("\\d+"))));',
 			output: header + 'test(t => t.notRegex(foo, new RegExp("\\d+")));',
-			errors: errors('notRegex')
+			errors: errors('notRegex'),
 		},
 		{
 			code: header + 'const regexp = RegExp("\\d+");\ntest(t => t.true(foo.search(regexp)));',
 			output: header + 'const regexp = RegExp("\\d+");\ntest(t => t.regex(foo, regexp));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		{
 			code: header + 'test(t => t.truthy(foo.match(new RegExp("\\d+"))));',
 			output: header + 'test(t => t.regex(foo, new RegExp("\\d+")));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		{
 			code: header + 'test(t => t.false(RegExp("\\d+").test("foo")));',
 			output: header + 'test(t => t.notRegex("foo", RegExp("\\d+")));',
-			errors: errors('notRegex')
+			errors: errors('notRegex'),
 		},
 		{
 			code: header + 'test(t => t.true(new RegExp("\\d+").test(foo())));',
 			output: header + 'test(t => t.regex(foo(), new RegExp("\\d+")));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		{
 			code: header + 'test(t => t.is(new RegExp("\\d+").test(foo), true));',
 			output: header + 'test(t => t.regex(foo, new RegExp("\\d+")));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		{
 			code: header + 'test(t => t.is(new RegExp("\\d+").test(foo), false));',
 			output: header + 'test(t => t.notRegex(foo, new RegExp("\\d+")));',
-			errors: errors('notRegex')
+			errors: errors('notRegex'),
 		},
 		{
 			code: header + 'const reg = RegExp("\\d+");\ntest(t => t.true(reg.test(foo.bar())));',
 			output: header + 'const reg = RegExp("\\d+");\ntest(t => t.regex(foo.bar(), reg));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		// The same as the above tests but with regex literal instead of string regex
 		{
 			code: header + 'test(t => t.true(new RegExp(/\\d+/).test("foo")));',
 			output: header + 'test(t => t.regex("foo", new RegExp(/\\d+/)));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		{
 			code: header + 'test(t => t.false(foo.search(new RegExp(/\\d+/))));',
 			output: header + 'test(t => t.notRegex(foo, new RegExp(/\\d+/)));',
-			errors: errors('notRegex')
+			errors: errors('notRegex'),
 		},
 		{
 			code: header + 'const regexp = RegExp(/\\d+/);\ntest(t => t.true(foo.search(regexp)));',
 			output: header + 'const regexp = RegExp(/\\d+/);\ntest(t => t.regex(foo, regexp));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		{
 			code: header + 'test(t => t.truthy(foo.match(new RegExp(/\\d+/))));',
 			output: header + 'test(t => t.regex(foo, new RegExp(/\\d+/)));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		{
 			code: header + 'test(t => t.false(RegExp(/\\d+/).test("foo")));',
 			output: header + 'test(t => t.notRegex("foo", RegExp(/\\d+/)));',
-			errors: errors('notRegex')
+			errors: errors('notRegex'),
 		},
 		{
 			code: header + 'test(t => t.true(new RegExp(/\\d+/).test(foo())));',
 			output: header + 'test(t => t.regex(foo(), new RegExp(/\\d+/)));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		{
 			code: header + 'test(t => t.is(new RegExp(/\\d+/).test(foo), true));',
 			output: header + 'test(t => t.regex(foo, new RegExp(/\\d+/)));',
-			errors: errors('regex')
+			errors: errors('regex'),
 		},
 		{
 			code: header + 'test(t => t.is(new RegExp(/\\d+/).test(foo), false));',
 			output: header + 'test(t => t.notRegex(foo, new RegExp(/\\d+/)));',
-			errors: errors('notRegex')
+			errors: errors('notRegex'),
 		},
 		{
 			code: header + 'const reg = RegExp(/\\d+/);\ntest(t => t.true(reg.test(foo.bar())));',
 			output: header + 'const reg = RegExp(/\\d+/);\ntest(t => t.regex(foo.bar(), reg));',
-			errors: errors('regex')
-		}
-	]
+			errors: errors('regex'),
+		},
+	],
 });
diff --git a/test/test-ended.js b/test/test-ended.js
deleted file mode 100644
index d8741c5..0000000
--- a/test/test-ended.js
+++ /dev/null
@@ -1,59 +0,0 @@
-const test = require('ava');
-const avaRuleTester = require('eslint-ava-rule-tester');
-const rule = require('../rules/test-ended');
-
-const ruleTester = avaRuleTester(test, {
-	env: {
-		es6: true
-	}
-});
-
-const errors = [{}];
-const header = 'const test = require(\'ava\');\n';
-
-ruleTester.run('test-ended', rule, {
-	valid: [
-		header + 'test.cb(function (t) { t.pass(); t.end(); });',
-		header + 'test.cb(function foo(t) { t.pass(); t.end(); });',
-		header + 'test.cb(t => { t.pass(); t.end(); });',
-		header + 'test.cb(t => { t.end(); });',
-		header + 'test.cb(t => { t.end(); t.pass(); });',
-		header + 'test.cb(t => { fn(t.end); });',
-		header + 'test.cb.only(t => { t.end(); });',
-		header + 'test.cb.skip.only(t => { t.end(); });',
-		header + 'test.only.cb.skip(t => { t.end(); });',
-		// Detecting that the called function has `end()` is not required #119
-		header + 'const macro = t => {};\ntest.cb(macro);',
-		// Shouldn't be triggered since it's not a callback test
-		header + 'test(t => { t.pass(); });',
-		// Shouldn't be triggered since it's not a test file
-		'test.cb(t => {});'
-	],
-	invalid: [
-		{
-			code: header + 'test.cb(function (t) { t.pass(); });',
-			errors
-		},
-		{
-			// Detecting that the called function has `end()` can turn into a recursive resolution nightmare
-			code: header + 'const macro = t => t.end();\ntest.cb((t) => macro(t));',
-			errors
-		},
-		{
-			code: header + 'test.cb(t => { t.pass(); });',
-			errors
-		},
-		{
-			code: header + 'test.cb(t => {});',
-			errors
-		},
-		{
-			code: header + 'test.cb.skip.only(t => {});',
-			errors
-		},
-		{
-			code: header + 'test.only.cb.skip(t => {});',
-			errors
-		}
-	]
-});
diff --git a/test/test-title-format.js b/test/test-title-format.js
index 215439b..dce851c 100644
--- a/test/test-title-format.js
+++ b/test/test-title-format.js
@@ -4,8 +4,8 @@ const rule = require('../rules/test-title-format');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const errors = [{}];
@@ -16,44 +16,44 @@ ruleTester.run('test-title-format', rule, {
 		header + 'test("Foo", t => { t.pass(); });',
 		{
 			code: header + 'test("Foo", t => { t.pass(); });',
-			options: [{format: '.'}]
+			options: [{format: '.'}],
 		},
 		{
 			code: header + 'test("Should pass tests.", t => { t.pass(); });',
-			options: [{format: '^Should .+\\.$'}]
+			options: [{format: '^Should .+\\.$'}],
 		},
 		{
 			code: header + 'test.todo("Should pass tests.");',
-			options: [{format: '^Should .+\\.$'}]
+			options: [{format: '^Should .+\\.$'}],
 		},
 		{
 			code: header + 'test(t => { t.pass(); });',
-			options: [{format: '^Should'}]
+			options: [{format: '^Should'}],
 		},
 		{
 			code: header + 'notTest("Foo", t => { t.pass(); });',
-			options: [{format: '^Should'}]
+			options: [{format: '^Should'}],
 		},
 		{
 			code: header + 'test(macro, t => { t.pass(); });',
-			options: [{format: '^Should'}]
+			options: [{format: '^Should'}],
 		},
 		// Shouldn't be triggered since it's not a test file
 		{
 			code: 'test("Test", t => { t.pass(); });',
-			options: [{format: '^Should'}]
-		}
+			options: [{format: '^Should'}],
+		},
 	],
 	invalid: [
 		{
 			code: header + 'test("Test something", t => { t.pass(); });',
 			options: [{format: '^Should'}],
-			errors
+			errors,
 		},
 		{
 			code: header + 'test.todo("Test something");',
 			options: [{format: '^Should'}],
-			errors
-		}
-	]
+			errors,
+		},
+	],
 });
diff --git a/test/test-title.js b/test/test-title.js
index 0b22cfd..54a1618 100644
--- a/test/test-title.js
+++ b/test/test-title.js
@@ -4,8 +4,8 @@ const rule = require('../rules/test-title');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const errors = [{}];
@@ -16,47 +16,38 @@ ruleTester.run('test-title', rule, {
 		header + 'test("my test name", t => { t.pass(); t.end(); });',
 		header + 'test(`my test name`, t => { t.pass(); t.end(); });',
 		header + 'test(\'my test name\', t => { t.pass(); t.end(); });',
-		header + 'test.cb("my test name", t => { t.pass(); t.end(); });',
 		header + 'test.todo("my test name");',
 		header + 'test.before(t => {});',
 		header + 'test.after(t => {});',
 		header + 'test.beforeEach(t => {});',
 		header + 'test.afterEach(t => {});',
-		header + 'test.cb.before(t => {}); test.before.cb(t => {});',
+		header + 'test.macro(t => {});',
 		header + 'notTest(t => { t.pass(); t.end(); });',
 		header + 'test([], arg1, arg2);',
 		header + 'test({}, arg1, arg2);',
 		// Shouldn't be triggered since it's not a test file
-		'test(t => {});'
+		'test(t => {});',
 	],
 	invalid: [
 		{
 			code: header + 'test(t => {});',
-			errors
+			errors,
 		},
 		{
 			code: header + 'test(t => {}, "my test name");',
-			errors
+			errors,
 		},
 		{
 			code: header + 'test(t => { t.pass(); t.end(); });',
-			errors
-		},
-		{
-			code: header + 'test.cb(t => { t.pass(); t.end(); });',
-			errors
-		},
-		{
-			code: header + 'test.cb.skip(t => { t.pass(); t.end(); });',
-			errors
+			errors,
 		},
 		{
 			code: header + 'test(t => { t.pass(); t.end(); });',
-			errors
+			errors,
 		},
 		{
 			code: header + 'test.todo();',
-			errors
-		}
-	]
+			errors,
+		},
+	],
 });
diff --git a/test/use-t-throws-async-well.js b/test/use-t-throws-async-well.js
index a4e8087..86d9b61 100644
--- a/test/use-t-throws-async-well.js
+++ b/test/use-t-throws-async-well.js
@@ -4,8 +4,8 @@ const rule = require('../rules/use-t-throws-async-well');
 
 const ruleTester = avaRuleTester(test, {
 	parserOptions: {
-		ecmaVersion: 2021
-	}
+		ecmaVersion: 2021,
+	},
 });
 
 const header = 'const test = require(\'ava\');\n';
@@ -40,34 +40,34 @@ ruleTester.run('use-t-throws-async-well', rule, {
 		asyncTestCase('let p = t.throwsAsync(f)'),
 		asyncTestCase('p = t.throwsAsync(f)'),
 		asyncTestCase('t.throwsAsync(f)', false), // Shouldn't be triggered since it's not a test file
-		syncTestCase('t.throwsAsync(f)', false) // Shouldn't be triggered since it's not a test file
+		syncTestCase('t.throwsAsync(f)', false), // Shouldn't be triggered since it's not a test file
 	],
 	invalid: [
 		{
 			code: syncTestCase('t.throwsAsync(f)'),
 			errors: [{
-				message: 'Use `await` with `t.throwsAsync()`.'
-			}]
+				message: 'Use `await` with `t.throwsAsync()`.',
+			}],
 		},
 		{
 			code: syncTestCase('t.notThrowsAsync(f)'),
 			errors: [{
-				message: 'Use `await` with `t.notThrowsAsync()`.'
-			}]
+				message: 'Use `await` with `t.notThrowsAsync()`.',
+			}],
 		},
 		{
 			code: asyncTestCase('t.throwsAsync(f)'),
 			output: asyncTestCase('await t.throwsAsync(f)'),
 			errors: [{
-				message: 'Use `await` with `t.throwsAsync()`.'
-			}]
+				message: 'Use `await` with `t.throwsAsync()`.',
+			}],
 		},
 		{
 			code: asyncTestCase('t.notThrowsAsync(f)'),
 			output: asyncTestCase('await t.notThrowsAsync(f)'),
 			errors: [{
-				message: 'Use `await` with `t.notThrowsAsync()`.'
-			}]
-		}
-	]
+				message: 'Use `await` with `t.notThrowsAsync()`.',
+			}],
+		},
+	],
 });
diff --git a/test/use-t-well.js b/test/use-t-well.js
index ef111a1..abbb9ff 100644
--- a/test/use-t-well.js
+++ b/test/use-t-well.js
@@ -4,8 +4,8 @@ const rule = require('../rules/use-t-well');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const header = 'const test = require(\'ava\');\n';
@@ -74,145 +74,145 @@ ruleTester.run('use-t-well', rule, {
 		testCase('t.like.skip(v, v)'),
 		// Shouldn't be triggered since it's not a test file
 		testCase('t.foo(a, a);', false),
-		testCase('t.foo;', false)
+		testCase('t.foo;', false),
 	],
 	invalid: [
 		{
 			code: testCase('t();'),
-			errors: [error('`t` is not a function.')]
+			errors: [error('`t` is not a function.')],
 		},
 		{
 			code: testCase('t.foo(a, a);'),
-			errors: [error('Unknown assertion method `.foo`.')]
+			errors: [error('Unknown assertion method `.foo`.')],
 		},
 		{
 			code: testCase('t.depEqual(a, a);'),
 			output: testCase('t.deepEqual(a, a);'),
-			errors: [error('Misspelled `.deepEqual` as `.depEqual`.')]
+			errors: [error('Misspelled `.deepEqual` as `.depEqual`.')],
 		},
 		{
 			code: testCase('t.deepEqual.skp(a, a);'),
 			output: testCase('t.deepEqual.skip(a, a);'),
-			errors: [error('Misspelled `.skip` as `.skp`.')]
+			errors: [error('Misspelled `.skip` as `.skp`.')],
 		},
 		{
 			code: testCase('t.context();'),
-			errors: [error('Unknown assertion method `.context`.')]
+			errors: [error('Unknown assertion method `.context`.')],
 		},
 		{
 			code: testCase('t.title();'),
-			errors: [error('Unknown assertion method `.title`.')]
+			errors: [error('Unknown assertion method `.title`.')],
 		},
 		{
 			code: testCase('t.a = 1;'),
-			errors: [error('Unknown member `.a`. Use `.context.a` instead.')]
+			errors: [error('Unknown member `.a`. Use `.context.a` instead.')],
 		},
 		{
 			code: testCase('t.ctx.a = 1;'),
-			errors: [error('Unknown member `.ctx`. Use `.context.ctx` instead.')]
+			errors: [error('Unknown member `.ctx`. Use `.context.ctx` instead.')],
 		},
 		{
 			code: testCase('t.deepEqu;'),
 			output: testCase('t.deepEqual;'),
-			errors: [error('Misspelled `.deepEqual` as `.deepEqu`.')]
+			errors: [error('Misspelled `.deepEqual` as `.deepEqu`.')],
 		},
 		{
 			code: testCase('t.deepEqual.is(a, a);'),
-			errors: [error('Can\'t chain assertion methods.')]
+			errors: [error('Can\'t chain assertion methods.')],
 		},
 		{
 			code: testCase('t.paln(1);'),
 			output: testCase('t.plan(1);'),
-			errors: [error('Misspelled `.plan` as `.paln`.')]
+			errors: [error('Misspelled `.plan` as `.paln`.')],
 		},
 		{
 			code: testCase('t.skip();'),
-			errors: [error('Missing assertion method.')]
+			errors: [error('Missing assertion method.')],
 		},
 		{
 			code: testCase('t.deepEqual.skip.skip(a, a);'),
 			output: testCase('t.deepEqual.skip(a, a);'),
-			errors: [error('Too many chained uses of `.skip`.')]
+			errors: [error('Too many chained uses of `.skip`.')],
 		},
 		{
 			code: testCase('t.falsey(a);'),
 			output: testCase('t.falsy(a);'),
-			errors: [error('Misspelled `.falsy` as `.falsey`.')]
+			errors: [error('Misspelled `.falsy` as `.falsey`.')],
 		},
 		{
 			code: testCase('t.truthey(a);'),
 			output: testCase('t.truthy(a);'),
-			errors: [error('Misspelled `.truthy` as `.truthey`.')]
+			errors: [error('Misspelled `.truthy` as `.truthey`.')],
 		},
 		{
 			code: testCase('t.deepequal(a, {});'),
 			output: testCase('t.deepEqual(a, {});'),
-			errors: [error('Misspelled `.deepEqual` as `.deepequal`.')]
+			errors: [error('Misspelled `.deepEqual` as `.deepequal`.')],
 		},
 		{
 			code: testCase('t.contxt;'),
 			output: testCase('t.context;'),
-			errors: [error('Misspelled `.context` as `.contxt`.')]
+			errors: [error('Misspelled `.context` as `.contxt`.')],
 		},
 		{
 			code: testCase('t.notdeepEqual(a, {});'),
 			output: testCase('t.notDeepEqual(a, {});'),
-			errors: [error('Misspelled `.notDeepEqual` as `.notdeepEqual`.')]
+			errors: [error('Misspelled `.notDeepEqual` as `.notdeepEqual`.')],
 		},
 		{
 			code: testCase('t.throw(a);'),
 			output: testCase('t.throws(a);'),
-			errors: [error('Misspelled `.throws` as `.throw`.')]
+			errors: [error('Misspelled `.throws` as `.throw`.')],
 		},
 		{
 			code: testCase('t.notThrow(a);'),
 			output: testCase('t.notThrows(a);'),
-			errors: [error('Misspelled `.notThrows` as `.notThrow`.')]
+			errors: [error('Misspelled `.notThrows` as `.notThrow`.')],
 		},
 		{
 			code: testCase('t.throwAsync(a);'),
 			output: testCase('t.throwsAsync(a);'),
-			errors: [error('Misspelled `.throwsAsync` as `.throwAsync`.')]
+			errors: [error('Misspelled `.throwsAsync` as `.throwAsync`.')],
 		},
 		{
 			code: testCase('t.notthrowAsync(a);'),
 			output: testCase('t.notThrowsAsync(a);'),
-			errors: [error('Misspelled `.notThrowsAsync` as `.notthrowAsync`.')]
+			errors: [error('Misspelled `.notThrowsAsync` as `.notthrowAsync`.')],
 		},
 		{
 			code: testCase('t.regexp(a, /r/);'),
 			output: testCase('t.regex(a, /r/);'),
-			errors: [error('Misspelled `.regex` as `.regexp`.')]
+			errors: [error('Misspelled `.regex` as `.regexp`.')],
 		},
 		{
 			code: testCase('t.notregexp(a, /r/);'),
 			output: testCase('t.notRegex(a, /r/);'),
-			errors: [error('Misspelled `.notRegex` as `.notregexp`.')]
+			errors: [error('Misspelled `.notRegex` as `.notregexp`.')],
 		},
 		{
 			code: testCase('t.contxt.foo = 1;'),
 			output: testCase('t.context.foo = 1;'),
-			errors: [error('Misspelled `.context` as `.contxt`.')]
+			errors: [error('Misspelled `.context` as `.contxt`.')],
 		},
 
 		{
 			code: testCase('t.skip.deepEqual(a, a);'),
 			output: testCase('t.deepEqual.skip(a, a);'),
-			errors: [error('`.skip` modifier should be the last in chain.')]
+			errors: [error('`.skip` modifier should be the last in chain.')],
 		},
 		{
 			code: testCase('t.skp.deepEqual(a, a);'),
 			output: testCase('t.skip.deepEqual(a, a);'),
-			errors: [error('Misspelled `.skip` as `.skp`.')]
+			errors: [error('Misspelled `.skip` as `.skp`.')],
 		},
 		{
 			code: testCase('t.deepEqual.context(a, a);'),
-			errors: [error('Unknown assertion method `.context`.')]
+			errors: [error('Unknown assertion method `.context`.')],
 		},
 		{
 			code: testCase('t.lik(a, a);'),
 			output: testCase('t.like(a, a);'),
-			errors: [error('Misspelled `.like` as `.lik`.')]
-		}
-	]
+			errors: [error('Misspelled `.like` as `.lik`.')],
+		},
+	],
 });
diff --git a/test/use-t.js b/test/use-t.js
index 2471538..b18bcf1 100644
--- a/test/use-t.js
+++ b/test/use-t.js
@@ -4,19 +4,15 @@ const rule = require('../rules/use-t');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
+		es6: true,
 	},
 	parserOptions: {
-		sourceType: 'module'
-	}
+		sourceType: 'module',
+	},
 });
 
 const parameterNotNamedTErrors = [{
-	message: 'Test parameter should be named `t`.'
-}];
-
-const tooManyParametersErrors = [{
-	message: 'Test should only have one parameter named `t`.'
+	message: 'Test parameter should be named `t`.',
 }];
 
 const header = 'const test = require(\'ava\');\n';
@@ -26,45 +22,40 @@ ruleTester.run('use-t', rule, {
 		header + 'test();',
 		header + 'test(() => {});',
 		header + 'test(t => {});',
-		header + 'test.cb(t => {});',
-		// Header + 'test("test name", t => {});',
+		header + 'test("test name", t => {});',
+		header + 'test((t, foo) => {});',
 		header + 'test(function (t) {});',
 		header + 'test(testFunction);',
+		header + 'test.macro(testFunction);',
+		header + 'test.macro(t => {});',
+		header + 'test.macro({exec: t => {}, title: () => "title"});',
 		header + 'test.todo("test name");',
 		// Shouldn't be triggered since it's not a test file
 		'test(foo => {});',
 		header + 'test(macro, arg1, (p1) => {})',
 		header + 'test("name", macro, arg1, (p1) => {})',
-		header + 'test("name", macro, (p1) => {})'
+		header + 'test("name", macro, (p1) => {})',
 	],
 	invalid: [
 		{
 			code: header + 'test(foo => {});',
-			errors: parameterNotNamedTErrors
+			errors: parameterNotNamedTErrors,
 		},
 		{
 			code: header + 'test("test name", foo => {});',
-			errors: parameterNotNamedTErrors
-		},
-		{
-			code: header + 'test.cb(foo => { foo.end(); });',
-			errors: parameterNotNamedTErrors
+			errors: parameterNotNamedTErrors,
 		},
 		{
 			code: header + 'test(function (foo) {});',
-			errors: parameterNotNamedTErrors
+			errors: parameterNotNamedTErrors,
 		},
 		{
-			code: header + 'test((t, foo) => {});',
-			errors: tooManyParametersErrors
+			code: header + 'test.macro(function (foo) {});',
+			errors: parameterNotNamedTErrors,
 		},
 		{
-			code: header + 'test((foo, t) => {});',
-			errors: tooManyParametersErrors
+			code: header + 'test.macro({ exec(foo) {} });',
+			errors: parameterNotNamedTErrors,
 		},
-		{
-			code: header + 'test("test name", (t, foo) => {});',
-			errors: tooManyParametersErrors
-		}
-	]
+	],
 });
diff --git a/test/use-test.js b/test/use-test.js
index 812e105..71f1559 100644
--- a/test/use-test.js
+++ b/test/use-test.js
@@ -4,11 +4,11 @@ const rule = require('../rules/use-test');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
+		es6: true,
 	},
 	parserOptions: {
-		sourceType: 'module'
-	}
+		sourceType: 'module',
+	},
 });
 
 const errors = [{}];
@@ -38,88 +38,88 @@ ruleTester.run('use-test', rule, {
 		{code: 'const anyTest = require(\'foo\');', filename: 'file.tsx'},
 		{code: 'import anyTest from \'ava\';', filename: 'file.tsx'},
 		{code: 'import anyTest, {} from \'ava\';', filename: 'file.tsx'},
-		{code: 'import anyTest from \'foo\';', filename: 'file.tsx'}
+		{code: 'import anyTest from \'foo\';', filename: 'file.tsx'},
 	],
 	invalid: [
 		{
 			code: 'var ava = require(\'ava\');',
 			errors,
-			filename: 'file.ts'
+			filename: 'file.ts',
 		},
 		{
 			code: 'let ava = require(\'ava\');',
 			errors,
-			filename: 'file.ts'
+			filename: 'file.ts',
 		},
 		{
 			code: 'const ava = require(\'ava\');',
 			errors,
-			filename: 'file.ts'
+			filename: 'file.ts',
 		},
 		{
 			code: 'const a = 1, ava = require(\'ava\'), b = 2;',
 			errors,
-			filename: 'file.ts'
+			filename: 'file.ts',
 		},
 		{
 			code: 'import ava from \'ava\';',
 			errors,
-			filename: 'file.ts'
+			filename: 'file.ts',
 		},
 		{
 			code: 'var anyTest = require(\'ava\');',
 			errors,
-			filename: 'file.js'
+			filename: 'file.js',
 		},
 		{
 			code: 'var ava = require(\'ava\');',
 			errors,
-			filename: 'file.ts'
+			filename: 'file.ts',
 		},
 		{
 			code: 'let ava = require(\'ava\');',
 			errors,
-			filename: 'file.ts'
+			filename: 'file.ts',
 		},
 		{
 			code: 'const ava = require(\'ava\');',
 			errors,
-			filename: 'file.ts'
+			filename: 'file.ts',
 		},
 		{
 			code: 'const a = 1, ava = require(\'ava\'), b = 2;',
 			errors,
-			filename: 'file.ts'
+			filename: 'file.ts',
 		},
 		{
 			code: 'import ava from \'ava\';',
 			errors,
-			filename: 'file.ts'
+			filename: 'file.ts',
 		},
 		{
 			code: 'var ava = require(\'ava\');',
 			errors,
-			filename: 'file.tsx'
+			filename: 'file.tsx',
 		},
 		{
 			code: 'let ava = require(\'ava\');',
 			errors,
-			filename: 'file.tsx'
+			filename: 'file.tsx',
 		},
 		{
 			code: 'const ava = require(\'ava\');',
 			errors,
-			filename: 'file.tsx'
+			filename: 'file.tsx',
 		},
 		{
 			code: 'const a = 1, ava = require(\'ava\'), b = 2;',
 			errors,
-			filename: 'file.tsx'
+			filename: 'file.tsx',
 		},
 		{
 			code: 'import ava from \'ava\';',
 			errors,
-			filename: 'file.tsx'
-		}
-	]
+			filename: 'file.tsx',
+		},
+	],
 });
diff --git a/test/use-true-false.js b/test/use-true-false.js
index 67e97b2..ba327a8 100644
--- a/test/use-true-false.js
+++ b/test/use-true-false.js
@@ -4,16 +4,16 @@ const rule = require('../rules/use-true-false');
 
 const ruleTester = avaRuleTester(test, {
 	env: {
-		es6: true
-	}
+		es6: true,
+	},
 });
 
 const trueErrors = [{
-	message: '`t.true()` should be used instead of `t.truthy()`.'
+	message: '`t.true()` should be used instead of `t.truthy()`.',
 }];
 
 const falseErrors = [{
-	message: '`t.false()` should be used instead of `t.falsy()`.'
+	message: '`t.false()` should be used instead of `t.falsy()`.',
 }];
 
 const header = 'const test = require(\'ava\');\n';
@@ -56,68 +56,68 @@ ruleTester.run('use-true-false', rule, {
 		testCase('foo.t.truthy(true)'),
 		testCase('foo.t.falsy(false)'),
 		// Shouldn't be triggered since it's not a test file
-		testCase('t.truthy(value === 1)', false)
+		testCase('t.truthy(value === 1)', false),
 	],
 	invalid: [
 		{
 			code: testCase('t.truthy(true)'),
-			errors: trueErrors
+			errors: trueErrors,
 		},
 		{
 			code: testCase('t.truthy(false)'),
-			errors: trueErrors
+			errors: trueErrors,
 		},
 		{
 			code: testCase('t.truthy(value == 1)'),
-			errors: trueErrors
+			errors: trueErrors,
 		},
 		{
 			code: testCase('t.truthy(value === 1)'),
-			errors: trueErrors
+			errors: trueErrors,
 		},
 		{
 			code: testCase('t.truthy(value != 1)'),
-			errors: trueErrors
+			errors: trueErrors,
 		},
 		{
 			code: testCase('t.truthy(value !== 1)'),
-			errors: trueErrors
+			errors: trueErrors,
 		},
 		{
 			code: testCase('t.truthy(value < 1)'),
-			errors: trueErrors
+			errors: trueErrors,
 		},
 		{
 			code: testCase('t.truthy(value <= 1)'),
-			errors: trueErrors
+			errors: trueErrors,
 		},
 		{
 			code: testCase('t.truthy(value > 1)'),
-			errors: trueErrors
+			errors: trueErrors,
 		},
 		{
 			code: testCase('t.truthy(value >= 1)'),
-			errors: trueErrors
+			errors: trueErrors,
 		},
 		{
 			code: testCase('t.truthy(!value)'),
-			errors: trueErrors
+			errors: trueErrors,
 		},
 		{
 			code: testCase('t.truthy(!!value)'),
-			errors: trueErrors
+			errors: trueErrors,
 		},
 		{
 			code: testCase('t.truthy(Array.isArray(value))'),
-			errors: trueErrors
+			errors: trueErrors,
 		},
 		{
 			code: testCase('t.truthy(isFinite(3))'),
-			errors: trueErrors
+			errors: trueErrors,
 		},
 		{
 			code: testCase('t.falsy(value === 1)'),
-			errors: falseErrors
-		}
-	]
+			errors: falseErrors,
+		},
+	],
 });