Repository: newrelic/newrelic-node-apollo-server-plugin
Pull request #247 (2023-05-19 13:57:34)

feat(metrics): add a new typed resolve metric
## Proposed Release Notes

* feat(metrics): add a new typed resolve metric

## Links

* Closes NEWRELIC-8656

## Details

All of the commit messages:

* chore(package): update dependencies

We have some outdated dependencies according to `npm audit`.

* chore(tests): replace deprecated `t.matches` with `t.match`

This silences a tap warning.

* chore(tests): silence lambda tests

This was outputting to stdout the lambda payload. We don't need to see
it during a test.

* feat(metrics): add a new typed resolve metric

I originally thought we needed a full path, but upon further
consideration, what our users really want here is not a story of how
the field was queried (that's the path) but rather what type the field
belongs to. That should be enough to disambiguate in the intended
case.



Patch:
diff --git a/lib/create-plugin.js b/lib/create-plugin.js
index cdf80ae..48ebd57 100644
--- a/lib/create-plugin.js
+++ b/lib/create-plugin.js
@@ -17,6 +17,7 @@ const CATEGORY = 'GraphQL'
 const FRAMEWORK = 'ApolloServer'
 const OPERATION_PREFIX = CATEGORY + '/operation/' + FRAMEWORK
 const RESOLVE_PREFIX = CATEGORY + '/resolve/' + FRAMEWORK
+const TYPED_RESOLVE_PREFIX = CATEGORY + '/typedResolve/' + FRAMEWORK
 const BATCH_PREFIX = 'batch'
 
 const DEFAULT_OPERATION_NAME = `${OPERATION_PREFIX}/<unknown>`
@@ -420,6 +421,16 @@ function recordResolveSegment(segment, scope) {
     const fieldNameMetric = `${RESOLVE_PREFIX}/${fieldName}`
     createMetricPairs(transaction, fieldNameMetric, scope, duration, exclusive)
   }
+
+  const fieldType = attributes[PARENT_TYPE_ATTR]
+
+  // We therefore also record the field with typename. This can be
+  // helpful in case two field names happen to match but are scoped to
+  // different types.
+  if (fieldType) {
+    const typedFieldMetric = `${TYPED_RESOLVE_PREFIX}/${fieldType}.${fieldName}`
+    createMetricPairs(transaction, typedFieldMetric, scope, duration, exclusive)
+  }
 }
 
 function filterSelectionsForDeepestPath(selections) {
diff --git a/package-lock.json b/package-lock.json
index 5d80e65..1a25a00 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,7 +12,7 @@
         "@apollo/server": "^4.1.1",
         "@newrelic/eslint-config": "^0.0.2",
         "@newrelic/newrelic-oss-cli": "^0.1.2",
-        "@newrelic/test-utilities": "^7.3.0",
+        "@newrelic/test-utilities": "^7.3.1",
         "apollo-server": "^3.11.1",
         "c8": "^7.12.0",
         "eslint": "^7.32.0",
@@ -27,7 +27,7 @@
         "newrelic": "^9.14.0",
         "prettier": "^2.3.2",
         "sinon": "^11.1.2",
-        "tap": "^16.0.1",
+        "tap": "^16.3.4",
         "tsd": "^0.18.0"
       },
       "engines": {
@@ -1077,9 +1077,9 @@
       }
     },
     "node_modules/@newrelic/test-utilities": {
-      "version": "7.3.0",
-      "resolved": "https://registry.npmjs.org/@newrelic/test-utilities/-/test-utilities-7.3.0.tgz",
-      "integrity": "sha512-hIP2/iJgv1EZrNNB3AQQxRAIsRYu4Gq6oAumdodhynk4FRYLcGRuMkCJqFNHcqAJSKeK8I3h/lxj+1BObQwxhQ==",
+      "version": "7.3.1",
+      "resolved": "https://registry.npmjs.org/@newrelic/test-utilities/-/test-utilities-7.3.1.tgz",
+      "integrity": "sha512-QelNCNMF+bWvkcx98PPeaLAiiNZsTsJ6LIq+dLiJ1ZvvWwh8uuoiavm1Kl3a34zvdTFb6HInX2BTDKWvrZ7K3g==",
       "dev": true,
       "dependencies": {
         "async": "^3.2.3",
@@ -6772,9 +6772,9 @@
       }
     },
     "node_modules/jackspeak": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-1.4.1.tgz",
-      "integrity": "sha512-npN8f+M4+IQ8xD3CcWi3U62VQwKlT3Tj4GxbdT/fYTmeogD9eBF9OFdpoFG/VPNoshRjPUijdkp/p2XrzUHaVg==",
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-1.4.2.tgz",
+      "integrity": "sha512-GHeGTmnuaHnvS+ZctRB01bfxARuu9wW83ENbuiweu07SFcVlZrJpcshSre/keGT7YGBhLHg/+rXCNSrsEHKU4Q==",
       "dev": true,
       "dependencies": {
         "cliui": "^7.0.4"
@@ -9992,9 +9992,9 @@
       }
     },
     "node_modules/tap": {
-      "version": "16.3.0",
-      "resolved": "https://registry.npmjs.org/tap/-/tap-16.3.0.tgz",
-      "integrity": "sha512-J9GffPUAbX6FnWbQ/jj7ktzd9nnDFP1fH44OzidqOmxUfZ1hPLMOvpS99LnDiP0H2mO8GY3kGN5XoY0xIKbNFA==",
+      "version": "16.3.4",
+      "resolved": "https://registry.npmjs.org/tap/-/tap-16.3.4.tgz",
+      "integrity": "sha512-SAexdt2ZF4XBgye6TPucFI2y7VE0qeFXlXucJIV1XDPCs+iJodk0MYacr1zR6Ycltzz7PYg8zrblDXKbAZM2LQ==",
       "bundleDependencies": [
         "ink",
         "treport",
@@ -10005,18 +10005,18 @@
       "dev": true,
       "dependencies": {
         "@isaacs/import-jsx": "^4.0.1",
-        "@types/react": "^17",
+        "@types/react": "^17.0.52",
         "chokidar": "^3.3.0",
         "findit": "^2.0.0",
         "foreground-child": "^2.0.0",
         "fs-exists-cached": "^1.0.0",
-        "glob": "^7.1.6",
+        "glob": "^7.2.3",
         "ink": "^3.2.0",
         "isexe": "^2.0.0",
-        "istanbul-lib-processinfo": "^2.0.2",
-        "jackspeak": "^1.4.1",
+        "istanbul-lib-processinfo": "^2.0.3",
+        "jackspeak": "^1.4.2",
         "libtap": "^1.4.0",
-        "minipass": "^3.1.1",
+        "minipass": "^3.3.4",
         "mkdirp": "^1.0.4",
         "nyc": "^15.1.0",
         "opener": "^1.5.1",
@@ -10025,10 +10025,10 @@
         "signal-exit": "^3.0.6",
         "source-map-support": "^0.5.16",
         "tap-mocha-reporter": "^5.0.3",
-        "tap-parser": "^11.0.1",
-        "tap-yaml": "^1.0.0",
+        "tap-parser": "^11.0.2",
+        "tap-yaml": "^1.0.2",
         "tcompare": "^5.0.7",
-        "treport": "^3.0.3",
+        "treport": "^3.0.4",
         "which": "^2.0.2"
       },
       "bin": {
@@ -10102,9 +10102,9 @@
       }
     },
     "node_modules/tap-parser": {
-      "version": "11.0.1",
-      "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-11.0.1.tgz",
-      "integrity": "sha512-5ow0oyFOnXVSALYdidMX94u0GEjIlgc/BPFYLx0yRh9hb8+cFGNJqJzDJlUqbLOwx8+NBrIbxCWkIQi7555c0w==",
+      "version": "11.0.2",
+      "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-11.0.2.tgz",
+      "integrity": "sha512-6qGlC956rcORw+fg7Fv1iCRAY8/bU9UabUAhs3mXRH6eRmVZcNPLheSXCYaVaYeSwx5xa/1HXZb1537YSvwDZg==",
       "dev": true,
       "dependencies": {
         "events-to-array": "^1.0.1",
@@ -10119,12 +10119,12 @@
       }
     },
     "node_modules/tap-yaml": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-1.0.0.tgz",
-      "integrity": "sha512-Rxbx4EnrWkYk0/ztcm5u3/VznbyFJpyXO12dDBHKWiDVxy7O2Qw6MRrwO5H6Ww0U5YhRY/4C/VzWmFPhBQc4qQ==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-1.0.2.tgz",
+      "integrity": "sha512-GegASpuqBnRNdT1U+yuUPZ8rEU64pL35WPBpCISWwff4dErS2/438barz7WFJl4Nzh3Y05tfPidZnH+GaV1wMg==",
       "dev": true,
       "dependencies": {
-        "yaml": "^1.5.0"
+        "yaml": "^1.10.2"
       }
     },
     "node_modules/tap/node_modules/@ampproject/remapping": {
@@ -10601,7 +10601,7 @@
       "license": "MIT"
     },
     "node_modules/tap/node_modules/@types/react": {
-      "version": "17.0.41",
+      "version": "17.0.52",
       "dev": true,
       "inBundle": true,
       "license": "MIT",
@@ -11040,7 +11040,7 @@
       }
     },
     "node_modules/tap/node_modules/glob": {
-      "version": "7.2.0",
+      "version": "7.2.3",
       "dev": true,
       "inBundle": true,
       "license": "ISC",
@@ -11048,7 +11048,7 @@
         "fs.realpath": "^1.0.0",
         "inflight": "^1.0.4",
         "inherits": "2",
-        "minimatch": "^3.0.4",
+        "minimatch": "^3.1.1",
         "once": "^1.3.0",
         "path-is-absolute": "^1.0.0"
       },
@@ -11255,7 +11255,7 @@
       }
     },
     "node_modules/tap/node_modules/json5": {
-      "version": "2.2.1",
+      "version": "2.2.3",
       "dev": true,
       "inBundle": true,
       "license": "MIT",
@@ -11333,7 +11333,7 @@
       }
     },
     "node_modules/tap/node_modules/minipass": {
-      "version": "3.1.6",
+      "version": "3.3.4",
       "dev": true,
       "inBundle": true,
       "license": "ISC",
@@ -11730,7 +11730,7 @@
       }
     },
     "node_modules/tap/node_modules/tap-parser": {
-      "version": "11.0.1",
+      "version": "11.0.2",
       "dev": true,
       "inBundle": true,
       "license": "MIT",
@@ -11747,12 +11747,12 @@
       }
     },
     "node_modules/tap/node_modules/tap-yaml": {
-      "version": "1.0.0",
+      "version": "1.0.2",
       "dev": true,
       "inBundle": true,
       "license": "ISC",
       "dependencies": {
-        "yaml": "^1.5.0"
+        "yaml": "^1.10.2"
       }
     },
     "node_modules/tap/node_modules/to-fast-properties": {
@@ -11765,7 +11765,7 @@
       }
     },
     "node_modules/tap/node_modules/treport": {
-      "version": "3.0.3",
+      "version": "3.0.4",
       "dev": true,
       "inBundle": true,
       "license": "ISC",
@@ -11776,6 +11776,7 @@
         "ink": "^3.2.0",
         "ms": "^2.1.2",
         "tap-parser": "^11.0.0",
+        "tap-yaml": "^1.0.0",
         "unicode-length": "^2.0.2"
       },
       "peerDependencies": {
@@ -13446,9 +13447,9 @@
       "requires": {}
     },
     "@newrelic/test-utilities": {
-      "version": "7.3.0",
-      "resolved": "https://registry.npmjs.org/@newrelic/test-utilities/-/test-utilities-7.3.0.tgz",
-      "integrity": "sha512-hIP2/iJgv1EZrNNB3AQQxRAIsRYu4Gq6oAumdodhynk4FRYLcGRuMkCJqFNHcqAJSKeK8I3h/lxj+1BObQwxhQ==",
+      "version": "7.3.1",
+      "resolved": "https://registry.npmjs.org/@newrelic/test-utilities/-/test-utilities-7.3.1.tgz",
+      "integrity": "sha512-QelNCNMF+bWvkcx98PPeaLAiiNZsTsJ6LIq+dLiJ1ZvvWwh8uuoiavm1Kl3a34zvdTFb6HInX2BTDKWvrZ7K3g==",
       "dev": true,
       "requires": {
         "async": "^3.2.3",
@@ -17801,9 +17802,9 @@
       }
     },
     "jackspeak": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-1.4.1.tgz",
-      "integrity": "sha512-npN8f+M4+IQ8xD3CcWi3U62VQwKlT3Tj4GxbdT/fYTmeogD9eBF9OFdpoFG/VPNoshRjPUijdkp/p2XrzUHaVg==",
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-1.4.2.tgz",
+      "integrity": "sha512-GHeGTmnuaHnvS+ZctRB01bfxARuu9wW83ENbuiweu07SFcVlZrJpcshSre/keGT7YGBhLHg/+rXCNSrsEHKU4Q==",
       "dev": true,
       "requires": {
         "cliui": "^7.0.4"
@@ -20282,24 +20283,24 @@
       }
     },
     "tap": {
-      "version": "16.3.0",
-      "resolved": "https://registry.npmjs.org/tap/-/tap-16.3.0.tgz",
-      "integrity": "sha512-J9GffPUAbX6FnWbQ/jj7ktzd9nnDFP1fH44OzidqOmxUfZ1hPLMOvpS99LnDiP0H2mO8GY3kGN5XoY0xIKbNFA==",
+      "version": "16.3.4",
+      "resolved": "https://registry.npmjs.org/tap/-/tap-16.3.4.tgz",
+      "integrity": "sha512-SAexdt2ZF4XBgye6TPucFI2y7VE0qeFXlXucJIV1XDPCs+iJodk0MYacr1zR6Ycltzz7PYg8zrblDXKbAZM2LQ==",
       "dev": true,
       "requires": {
         "@isaacs/import-jsx": "^4.0.1",
-        "@types/react": "^17",
+        "@types/react": "^17.0.52",
         "chokidar": "^3.3.0",
         "findit": "^2.0.0",
         "foreground-child": "^2.0.0",
         "fs-exists-cached": "^1.0.0",
-        "glob": "^7.1.6",
+        "glob": "^7.2.3",
         "ink": "^3.2.0",
         "isexe": "^2.0.0",
-        "istanbul-lib-processinfo": "^2.0.2",
-        "jackspeak": "^1.4.1",
+        "istanbul-lib-processinfo": "^2.0.3",
+        "jackspeak": "^1.4.2",
         "libtap": "^1.4.0",
-        "minipass": "^3.1.1",
+        "minipass": "^3.3.4",
         "mkdirp": "^1.0.4",
         "nyc": "^15.1.0",
         "opener": "^1.5.1",
@@ -20308,10 +20309,10 @@
         "signal-exit": "^3.0.6",
         "source-map-support": "^0.5.16",
         "tap-mocha-reporter": "^5.0.3",
-        "tap-parser": "^11.0.1",
-        "tap-yaml": "^1.0.0",
+        "tap-parser": "^11.0.2",
+        "tap-yaml": "^1.0.2",
         "tcompare": "^5.0.7",
-        "treport": "^3.0.3",
+        "treport": "^3.0.4",
         "which": "^2.0.2"
       },
       "dependencies": {
@@ -20633,7 +20634,7 @@
           "dev": true
         },
         "@types/react": {
-          "version": "17.0.41",
+          "version": "17.0.52",
           "bundled": true,
           "dev": true,
           "requires": {
@@ -20910,14 +20911,14 @@
           "dev": true
         },
         "glob": {
-          "version": "7.2.0",
+          "version": "7.2.3",
           "bundled": true,
           "dev": true,
           "requires": {
             "fs.realpath": "^1.0.0",
             "inflight": "^1.0.4",
             "inherits": "2",
-            "minimatch": "^3.0.4",
+            "minimatch": "^3.1.1",
             "once": "^1.3.0",
             "path-is-absolute": "^1.0.0"
           }
@@ -21050,7 +21051,7 @@
           "dev": true
         },
         "json5": {
-          "version": "2.2.1",
+          "version": "2.2.3",
           "bundled": true,
           "dev": true
         },
@@ -21097,7 +21098,7 @@
           }
         },
         "minipass": {
-          "version": "3.1.6",
+          "version": "3.3.4",
           "bundled": true,
           "dev": true,
           "requires": {
@@ -21362,7 +21363,7 @@
           }
         },
         "tap-parser": {
-          "version": "11.0.1",
+          "version": "11.0.2",
           "bundled": true,
           "dev": true,
           "requires": {
@@ -21372,11 +21373,11 @@
           }
         },
         "tap-yaml": {
-          "version": "1.0.0",
+          "version": "1.0.2",
           "bundled": true,
           "dev": true,
           "requires": {
-            "yaml": "^1.5.0"
+            "yaml": "^1.10.2"
           }
         },
         "to-fast-properties": {
@@ -21385,7 +21386,7 @@
           "dev": true
         },
         "treport": {
-          "version": "3.0.3",
+          "version": "3.0.4",
           "bundled": true,
           "dev": true,
           "requires": {
@@ -21395,6 +21396,7 @@
             "ink": "^3.2.0",
             "ms": "^2.1.2",
             "tap-parser": "^11.0.0",
+            "tap-yaml": "^1.0.0",
             "unicode-length": "^2.0.2"
           },
           "dependencies": {
@@ -21575,9 +21577,9 @@
       }
     },
     "tap-parser": {
-      "version": "11.0.1",
-      "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-11.0.1.tgz",
-      "integrity": "sha512-5ow0oyFOnXVSALYdidMX94u0GEjIlgc/BPFYLx0yRh9hb8+cFGNJqJzDJlUqbLOwx8+NBrIbxCWkIQi7555c0w==",
+      "version": "11.0.2",
+      "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-11.0.2.tgz",
+      "integrity": "sha512-6qGlC956rcORw+fg7Fv1iCRAY8/bU9UabUAhs3mXRH6eRmVZcNPLheSXCYaVaYeSwx5xa/1HXZb1537YSvwDZg==",
       "dev": true,
       "requires": {
         "events-to-array": "^1.0.1",
@@ -21586,12 +21588,12 @@
       }
     },
     "tap-yaml": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-1.0.0.tgz",
-      "integrity": "sha512-Rxbx4EnrWkYk0/ztcm5u3/VznbyFJpyXO12dDBHKWiDVxy7O2Qw6MRrwO5H6Ww0U5YhRY/4C/VzWmFPhBQc4qQ==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-1.0.2.tgz",
+      "integrity": "sha512-GegASpuqBnRNdT1U+yuUPZ8rEU64pL35WPBpCISWwff4dErS2/438barz7WFJl4Nzh3Y05tfPidZnH+GaV1wMg==",
       "dev": true,
       "requires": {
-        "yaml": "^1.5.0"
+        "yaml": "^1.10.2"
       }
     },
     "tar-fs": {
diff --git a/package.json b/package.json
index 830690b..f4edfdd 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,7 @@
     "@apollo/server": "^4.1.1",
     "@newrelic/eslint-config": "^0.0.2",
     "@newrelic/newrelic-oss-cli": "^0.1.2",
-    "@newrelic/test-utilities": "^7.3.0",
+    "@newrelic/test-utilities": "^7.3.1",
     "apollo-server": "^3.11.1",
     "c8": "^7.12.0",
     "eslint": "^7.32.0",
@@ -57,7 +57,7 @@
     "newrelic": "^9.14.0",
     "prettier": "^2.3.2",
     "sinon": "^11.1.2",
-    "tap": "^16.0.1",
+    "tap": "^16.3.4",
     "tsd": "^0.18.0"
   },
   "peerDependencies": {


Test patch:
diff --git a/tests/integration/metrics.test.js b/tests/integration/metrics.test.js
index 65546d2..39db041 100644
--- a/tests/integration/metrics.test.js
+++ b/tests/integration/metrics.test.js
@@ -14,6 +14,7 @@ const UNKNOWN_OPERATION = '<unknown>'
 
 const OPERATION_PREFIX = 'GraphQL/operation/ApolloServer'
 const RESOLVE_PREFIX = 'GraphQL/resolve/ApolloServer'
+const TYPED_RESOLVE_PREFIX = 'GraphQL/typedResolve/ApolloServer'
 
 const { setupApolloServerTests } = require('./apollo-server-setup')
 
@@ -53,7 +54,11 @@ function createMetricsTests(t) {
 
     helper.agent.once('transactionFinished', () => {
       const operationPart = `query/${expectedName}/hello`
-      t.metrics([`${OPERATION_PREFIX}/${operationPart}`, `${RESOLVE_PREFIX}/hello`])
+      t.metrics([
+        `${OPERATION_PREFIX}/${operationPart}`,
+        `${RESOLVE_PREFIX}/hello`,
+        `${TYPED_RESOLVE_PREFIX}/Query.hello`
+      ])
     })
 
     executeQuery(serverUrl, query, (err) => {
@@ -85,7 +90,10 @@ function createMetricsTests(t) {
         `${OPERATION_PREFIX}/${operationPart}`,
         `${RESOLVE_PREFIX}/libraries`,
         `${RESOLVE_PREFIX}/books`,
-        `${RESOLVE_PREFIX}/author`
+        `${RESOLVE_PREFIX}/author`,
+        `${TYPED_RESOLVE_PREFIX}/Query.libraries`,
+        `${TYPED_RESOLVE_PREFIX}/Library.books`,
+        `${TYPED_RESOLVE_PREFIX}/Book.author`
       ])
     })
 
@@ -126,12 +134,16 @@ function createMetricsTests(t) {
         `${OPERATION_PREFIX}/${operationPart1}`,
         `${RESOLVE_PREFIX}/library`,
         `${RESOLVE_PREFIX}/books`,
-        `${RESOLVE_PREFIX}/author`
+        `${RESOLVE_PREFIX}/author`,
+        `${TYPED_RESOLVE_PREFIX}/Query.libraries`,
+        `${TYPED_RESOLVE_PREFIX}/Library.books`,
+        `${TYPED_RESOLVE_PREFIX}/Book.author`
       ]
 
       const operationMetrics2 = [
         `${OPERATION_PREFIX}/${operationPart2}`,
-        `${RESOLVE_PREFIX}/addThing`
+        `${RESOLVE_PREFIX}/addThing`,
+        `${TYPED_RESOLVE_PREFIX}/Mutation.addThing`
       ]
 
       t.metrics([...operationMetrics1, ...operationMetrics2])
@@ -161,7 +173,10 @@ function createMetricsTests(t) {
         `${OPERATION_PREFIX}/${operationPart}`,
         `${RESOLVE_PREFIX}/libraries`,
         `${RESOLVE_PREFIX}/books`,
-        `${RESOLVE_PREFIX}/author`
+        `${RESOLVE_PREFIX}/author`,
+        `${TYPED_RESOLVE_PREFIX}/Query.libraries`,
+        `${TYPED_RESOLVE_PREFIX}/Library.books`,
+        `${TYPED_RESOLVE_PREFIX}/Book.author`
       ])
     })
 
@@ -230,7 +245,10 @@ function createMetricsTests(t) {
         `${OPERATION_PREFIX}/${operationPart}`,
         `${RESOLVE_PREFIX}/library`,
         `${RESOLVE_PREFIX}/books`,
-        `${RESOLVE_PREFIX}/author`
+        `${RESOLVE_PREFIX}/author`,
+        `${TYPED_RESOLVE_PREFIX}/Query.libraries`,
+        `${TYPED_RESOLVE_PREFIX}/Library.books`,
+        `${TYPED_RESOLVE_PREFIX}/Book.author`
       ])
     })
 
@@ -267,7 +285,10 @@ function createMetricsTests(t) {
         `${OPERATION_PREFIX}/${operationPart}`,
         `${RESOLVE_PREFIX}/library`,
         `${RESOLVE_PREFIX}/books`,
-        `${RESOLVE_PREFIX}/author`
+        `${RESOLVE_PREFIX}/author`,
+        `${TYPED_RESOLVE_PREFIX}/Query.libraries`,
+        `${TYPED_RESOLVE_PREFIX}/Library.books`,
+        `${TYPED_RESOLVE_PREFIX}/Book.author`
       ])
     })
 
diff --git a/tests/versioned/apollo-server-lambda/apollo-server-lambda-setup.js b/tests/versioned/apollo-server-lambda/apollo-server-lambda-setup.js
index 367f258..1b1744e 100644
--- a/tests/versioned/apollo-server-lambda/apollo-server-lambda-setup.js
+++ b/tests/versioned/apollo-server-lambda/apollo-server-lambda-setup.js
@@ -6,6 +6,7 @@
 'use strict'
 
 const tap = require('tap')
+const os = require('os')
 
 const agentTesting = require('../../agent-testing')
 const utils = require('@newrelic/test-utilities')
@@ -32,6 +33,7 @@ function setupApolloServerLambdaTests({ suiteName, createTests, pluginConfig },
      * distributed tracing.
      */
     agentTesting.temporarySetEnv(t, 'NEW_RELIC_ACCOUNT_ID', 'eeeeee')
+    agentTesting.temporarySetEnv(t, 'NEWRELIC_PIPE_PATH', os.devNull)
 
     t.beforeEach((t) => {
       const lambdaServerPkg = require('apollo-server-lambda')
diff --git a/tests/versioned/apollo-server-lambda/attributes-tests.js b/tests/versioned/apollo-server-lambda/attributes-tests.js
index 9bcd1c4..f225ea2 100644
--- a/tests/versioned/apollo-server-lambda/attributes-tests.js
+++ b/tests/versioned/apollo-server-lambda/attributes-tests.js
@@ -46,11 +46,7 @@ function createAttributesTests(t) {
       }
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
 
       const hasAttribute = Object.hasOwnProperty.bind(operationAttributes)
       t.notOk(hasAttribute('graphql.operation.name'))
@@ -65,11 +61,7 @@ function createAttributesTests(t) {
       }
 
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        resolveAttributes,
-        expectedResolveAttributes,
-        'should have field resolve attributes'
-      )
+      t.match(resolveAttributes, expectedResolveAttributes, 'should have field resolve attributes')
     })
 
     executeQueryAssertResult({
@@ -99,11 +91,7 @@ function createAttributesTests(t) {
       }
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
 
       const resolveHelloSegment = operationSegment.children[0]
 
@@ -115,11 +103,7 @@ function createAttributesTests(t) {
       }
 
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        resolveAttributes,
-        expectedResolveAttributes,
-        'should have field resolve attributes'
-      )
+      t.match(resolveAttributes, expectedResolveAttributes, 'should have field resolve attributes')
     })
 
     executeQueryAssertResult({
@@ -158,11 +142,7 @@ function createAttributesTests(t) {
       }
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
 
       const [resolveLibrariesSegment, resolveBooksSegment] = operationSegment.children
 
@@ -174,7 +154,7 @@ function createAttributesTests(t) {
       }
 
       const resolveLibrariesAttributes = resolveLibrariesSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
+      t.match(
         resolveLibrariesAttributes,
         expectedLibrariesAttributes,
         'should have field resolve attributes for libraries'
@@ -188,7 +168,7 @@ function createAttributesTests(t) {
       }
 
       const resolveBooksAttributes = resolveBooksSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
+      t.match(
         resolveBooksAttributes,
         expectedBooksAttributes,
         'should have field resolve attributes for books'
@@ -231,11 +211,7 @@ function createAttributesTests(t) {
       }
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
 
       const [resolveLibrariesSegment, resolveBooksSegment] = operationSegment.children
 
@@ -247,7 +223,7 @@ function createAttributesTests(t) {
       }
 
       const resolveLibrariesAttributes = resolveLibrariesSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
+      t.match(
         resolveLibrariesAttributes,
         expectedLibrariesAttributes,
         'should have field resolve attributes for libraries'
@@ -261,7 +237,7 @@ function createAttributesTests(t) {
       }
 
       const resolveBooksAttributes = resolveBooksSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
+      t.match(
         resolveBooksAttributes,
         expectedBooksAttributes,
         'should have field resolve attributes for books'
@@ -296,11 +272,7 @@ function createAttributesTests(t) {
       }
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
 
       const resolveHelloSegment = operationSegment.children[0]
 
@@ -312,11 +284,7 @@ function createAttributesTests(t) {
       }
 
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        resolveAttributes,
-        expectedResolveAttributes,
-        'should have field resolve attributes'
-      )
+      t.match(resolveAttributes, expectedResolveAttributes, 'should have field resolve attributes')
     })
 
     executeQueryAssertResult({
@@ -376,8 +344,8 @@ function createAttributesTests(t) {
 
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(resolveAttributes, { 'graphql.field.args.name': 'added thing!' })
-      t.matches(operationAttributes, { 'graphql.field.args.name': 'added thing!' })
+      t.match(resolveAttributes, { 'graphql.field.args.name': 'added thing!' })
+      t.match(operationAttributes, { 'graphql.field.args.name': 'added thing!' })
     })
 
     executeQueryAssertResult({
@@ -412,8 +380,8 @@ function createAttributesTests(t) {
       }
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(resolveAttributes, expectedArgAttributes)
-      t.matches(operationAttributes, expectedArgAttributes)
+      t.match(resolveAttributes, expectedArgAttributes)
+      t.match(operationAttributes, expectedArgAttributes)
     })
 
     executeQueryAssertResult({
@@ -457,8 +425,8 @@ function createAttributesTests(t) {
       }
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(resolveAttributes, expectedArgAttributes)
-      t.matches(operationAttributes, expectedArgAttributes)
+      t.match(resolveAttributes, expectedArgAttributes)
+      t.match(operationAttributes, expectedArgAttributes)
     })
 
     executeQueryJson({
@@ -489,11 +457,7 @@ function createAttributesTests(t) {
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
 
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
     })
 
     executeQueryAssertResult({
@@ -530,11 +494,7 @@ function createAttributesTests(t) {
       }
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
 
       const resolveHelloSegment = operationSegment.children[0]
 
@@ -546,11 +506,7 @@ function createAttributesTests(t) {
       }
 
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        resolveAttributes,
-        expectedResolveAttributes,
-        'should have field resolve attributes'
-      )
+      t.match(resolveAttributes, expectedResolveAttributes, 'should have field resolve attributes')
     })
 
     executeQueryAssertResult({
@@ -590,11 +546,7 @@ function createAttributesTests(t) {
       }
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
 
       const resolveHelloSegment = operationSegment.children[0]
 
@@ -606,11 +558,7 @@ function createAttributesTests(t) {
       }
 
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        resolveAttributes,
-        expectedResolveAttributes,
-        'should have field resolve attributes'
-      )
+      t.match(resolveAttributes, expectedResolveAttributes, 'should have field resolve attributes')
     })
 
     executeQueryAssertResult({
@@ -650,11 +598,7 @@ function createAttributesTests(t) {
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
 
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
       count++
     })
 
diff --git a/tests/versioned/attributes-tests.js b/tests/versioned/attributes-tests.js
index 1d5ae8e..52a4bd5 100644
--- a/tests/versioned/attributes-tests.js
+++ b/tests/versioned/attributes-tests.js
@@ -37,11 +37,7 @@ function createAttributesTests(t) {
       }
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
 
       const hasAttribute = Object.hasOwnProperty.bind(operationAttributes)
       t.notOk(hasAttribute('graphql.operation.name'))
@@ -56,11 +52,7 @@ function createAttributesTests(t) {
       }
 
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        resolveAttributes,
-        expectedResolveAttributes,
-        'should have field resolve attributes'
-      )
+      t.match(resolveAttributes, expectedResolveAttributes, 'should have field resolve attributes')
     })
 
     executeQuery(serverUrl, query, (err) => {
@@ -87,11 +79,7 @@ function createAttributesTests(t) {
       }
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
 
       const resolveHelloSegment = operationSegment.children[0]
 
@@ -103,11 +91,7 @@ function createAttributesTests(t) {
       }
 
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        resolveAttributes,
-        expectedResolveAttributes,
-        'should have field resolve attributes'
-      )
+      t.match(resolveAttributes, expectedResolveAttributes, 'should have field resolve attributes')
     })
 
     executeQuery(serverUrl, query, (err) => {
@@ -143,11 +127,7 @@ function createAttributesTests(t) {
       }
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
 
       const [resolveLibrariesSegment, resolveBooksSegment] = operationSegment.children
 
@@ -159,7 +139,7 @@ function createAttributesTests(t) {
       }
 
       const resolveLibrariesAttributes = resolveLibrariesSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
+      t.match(
         resolveLibrariesAttributes,
         expectedLibrariesAttributes,
         'should have field resolve attributes for libraries'
@@ -173,7 +153,7 @@ function createAttributesTests(t) {
       }
 
       const resolveBooksAttributes = resolveBooksSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
+      t.match(
         resolveBooksAttributes,
         expectedBooksAttributes,
         'should have field resolve attributes for books'
@@ -213,11 +193,7 @@ function createAttributesTests(t) {
       }
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
 
       const [resolveLibrariesSegment, resolveBooksSegment] = operationSegment.children
 
@@ -229,7 +205,7 @@ function createAttributesTests(t) {
       }
 
       const resolveLibrariesAttributes = resolveLibrariesSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
+      t.match(
         resolveLibrariesAttributes,
         expectedLibrariesAttributes,
         'should have field resolve attributes for libraries'
@@ -243,7 +219,7 @@ function createAttributesTests(t) {
       }
 
       const resolveBooksAttributes = resolveBooksSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
+      t.match(
         resolveBooksAttributes,
         expectedBooksAttributes,
         'should have field resolve attributes for books'
@@ -275,11 +251,7 @@ function createAttributesTests(t) {
       }
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
 
       const resolveHelloSegment = operationSegment.children[0]
 
@@ -291,11 +263,7 @@ function createAttributesTests(t) {
       }
 
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        resolveAttributes,
-        expectedResolveAttributes,
-        'should have field resolve attributes'
-      )
+      t.match(resolveAttributes, expectedResolveAttributes, 'should have field resolve attributes')
     })
 
     executeQuery(serverUrl, query, (err) => {
@@ -349,8 +317,8 @@ function createAttributesTests(t) {
 
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(resolveAttributes, { 'graphql.field.args.name': 'added thing!' })
-      t.matches(operationAttributes, { 'graphql.field.args.name': 'added thing!' })
+      t.match(resolveAttributes, { 'graphql.field.args.name': 'added thing!' })
+      t.match(operationAttributes, { 'graphql.field.args.name': 'added thing!' })
     })
 
     executeQuery(serverUrl, query, (err) => {
@@ -382,8 +350,8 @@ function createAttributesTests(t) {
       }
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(resolveAttributes, expectedArgAttributes)
-      t.matches(operationAttributes, expectedArgAttributes)
+      t.match(resolveAttributes, expectedArgAttributes)
+      t.match(operationAttributes, expectedArgAttributes)
     })
 
     executeQuery(serverUrl, query, (err) => {
@@ -423,7 +391,7 @@ function createAttributesTests(t) {
         'graphql.field.args.blee': 'second'
       }
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(resolveAttributes, expectedArgAttributes)
+      t.match(resolveAttributes, expectedArgAttributes)
     })
 
     executeJson(serverUrl, queryJson, (err) => {
@@ -451,11 +419,7 @@ function createAttributesTests(t) {
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
 
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
     })
 
     executeQuery(serverUrl, query, (err) => {
@@ -489,11 +453,7 @@ function createAttributesTests(t) {
       }
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
 
       const resolveHelloSegment = operationSegment.children[0]
 
@@ -505,11 +465,7 @@ function createAttributesTests(t) {
       }
 
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        resolveAttributes,
-        expectedResolveAttributes,
-        'should have field resolve attributes'
-      )
+      t.match(resolveAttributes, expectedResolveAttributes, 'should have field resolve attributes')
     })
 
     executeQuery(serverUrl, query, (err) => {
@@ -546,11 +502,7 @@ function createAttributesTests(t) {
       }
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
 
       const resolveHelloSegment = operationSegment.children[0]
 
@@ -562,11 +514,7 @@ function createAttributesTests(t) {
       }
 
       const resolveAttributes = resolveHelloSegment.attributes.get(SEGMENT_DESTINATION)
-      t.matches(
-        resolveAttributes,
-        expectedResolveAttributes,
-        'should have field resolve attributes'
-      )
+      t.match(resolveAttributes, expectedResolveAttributes, 'should have field resolve attributes')
     })
 
     executeQuery(serverUrl, query, (err) => {
@@ -603,11 +551,7 @@ function createAttributesTests(t) {
 
       const operationAttributes = operationSegment.attributes.get(SEGMENT_DESTINATION)
 
-      t.matches(
-        operationAttributes,
-        expectedOperationAttributes,
-        'should have operation attributes'
-      )
+      t.match(operationAttributes, expectedOperationAttributes, 'should have operation attributes')
       count++
     }