diff --git a/badge-maker/lib/badge-cli.spec.js b/badge-maker/lib/badge-cli.spec.mjs
similarity index 85%
rename from badge-maker/lib/badge-cli.spec.js
rename to badge-maker/lib/badge-cli.spec.mjs
index 13ea13aea92b405f2c70fa4e5a2e0b627fd2e8a9..b9d5fd5dcb7f96c6868be3134206d1d70fe3e931 100644
--- a/badge-maker/lib/badge-cli.spec.js
+++ b/badge-maker/lib/badge-cli.spec.mjs
@@ -1,9 +1,8 @@
 'use strict'
 
-const path = require('path')
-const { spawn } = require('child-process-promise')
-const { expect, use } = require('chai')
-use(require('chai-string'))
+import path from 'path'
+import { spawn } from 'child-process-promise'
+import { expect, use } from 'chai'
 use(require('sinon-chai'))
 
 function runCli(args) {
@@ -15,7 +14,7 @@ function runCli(args) {
 describe('The CLI', function () {
   it('should provide a help message', async function () {
     const { stdout } = await runCli([])
-    expect(stdout).to.startWith('Usage')
+    expect(stdout.startsWith('Usage')).to.be.true
   })
 
   it('should produce default badges', async function () {
diff --git a/badge-maker/lib/index.spec.js b/badge-maker/lib/index.spec.mjs
similarity index 97%
rename from badge-maker/lib/index.spec.js
rename to badge-maker/lib/index.spec.mjs
index d19185570de28545b41986c8fe727a146691f0ea..d1c508f37c081ecf700aeaf510a9dfe32cfdc122 100644
--- a/badge-maker/lib/index.spec.js
+++ b/badge-maker/lib/index.spec.mjs
@@ -1,7 +1,7 @@
 'use strict'
 
-const { expect } = require('chai')
-const { makeBadge, ValidationError } = require('.')
+import { expect } from 'chai'
+import { makeBadge, ValidationError } from '.'
 
 describe('makeBadge function', function () {
   it('should produce badge with valid input', async function () {
diff --git a/badge-maker/lib/make-badge.spec.js b/badge-maker/lib/make-badge.spec.mjs
similarity index 98%
rename from badge-maker/lib/make-badge.spec.js
rename to badge-maker/lib/make-badge.spec.mjs
index da28fcbf8520a8094b572a571388024bc91b22bf..fb9c3d96e1c298e36c3effb486077ef37c3c5c6f 100644
--- a/badge-maker/lib/make-badge.spec.js
+++ b/badge-maker/lib/make-badge.spec.mjs
@@ -1,10 +1,10 @@
 'use strict'
 
-const { test, given, forCases } = require('sazerac')
-const { expect } = require('chai')
-const snapshot = require('snap-shot-it')
-const prettier = require('prettier')
-const makeBadge = require('./make-badge')
+import { test, given, forCases } from 'sazerac'
+import { expect } from 'chai'
+import snapshot from 'snap-shot-it'
+import prettier from 'prettier'
+import makeBadge from './make-badge'
 
 async function expectBadgeToMatchSnapshot(format) {
   snapshot(await prettier.format(makeBadge(format), { parser: 'html' }))
diff --git a/core/base-service/base.spec.js b/core/base-service/base.spec.js
index a0f5b9d02b02d2e0fb482717a71ddcd9b63f5f8d..023b30b39b4b777807a00460993273e01ed8e195 100644
--- a/core/base-service/base.spec.js
+++ b/core/base-service/base.spec.js
@@ -1,5 +1,5 @@
 import Joi from 'joi'
-import chai from 'chai'
+import { expect, use } from 'chai'
 import sinon from 'sinon'
 import prometheus from 'prom-client'
 import chaiAsPromised from 'chai-as-promised'
@@ -16,8 +16,7 @@ import {
 import BaseService from './base.js'
 import { MetricHelper, MetricNames } from './metric-helper.js'
 import '../register-chai-plugins.spec.js'
-const { expect } = chai
-chai.use(chaiAsPromised)
+use(chaiAsPromised)
 
 const queryParamSchema = Joi.object({
   queryParamA: Joi.string(),
diff --git a/core/base-service/cache-headers.spec.js b/core/base-service/cache-headers.spec.js
index 0e1f508e32bd5aa99afd7653135f8fe781c083d0..1c22e5e1c0d3426193aef00585175df4e37fcd66 100644
--- a/core/base-service/cache-headers.spec.js
+++ b/core/base-service/cache-headers.spec.js
@@ -1,5 +1,5 @@
 import { test, given } from 'sazerac'
-import chai, { expect } from 'chai'
+import { expect, use } from 'chai'
 import sinon from 'sinon'
 import httpMocks from 'node-mocks-http'
 import chaiDatetime from 'chai-datetime'
@@ -10,7 +10,7 @@ import {
   setCacheHeadersForStaticResource,
   serverHasBeenUpSinceResourceCached,
 } from './cache-headers.js'
-chai.use(chaiDatetime)
+use(chaiDatetime)
 
 describe('Cache header functions', function () {
   let res
diff --git a/core/base-service/graphql.spec.js b/core/base-service/graphql.spec.js
index 7ebe8427a87c35d7753dd48bbc2d6fa522fd2d9f..41dbd21d0eed32eb3aab5cb354497d77a998cc9a 100644
--- a/core/base-service/graphql.spec.js
+++ b/core/base-service/graphql.spec.js
@@ -17,8 +17,14 @@ describe('mergeQueries function', function () {
           }
         `),
       ),
-    ).to.equalIgnoreSpaces(
-      'query ($param: String!) { foo(param: $param) { bar } }',
+    ).to.equal(
+      print(gql`
+        query ($param: String!) {
+          foo(param: $param) {
+            bar
+          }
+        }
+      `),
     )
 
     expect(
@@ -38,8 +44,15 @@ describe('mergeQueries function', function () {
           `,
         ),
       ),
-    ).to.equalIgnoreSpaces(
-      'query ($param: String!) { foo(param: $param) { bar } baz }',
+    ).to.equal(
+      print(gql`
+        query ($param: String!) {
+          foo(param: $param) {
+            bar
+          }
+          baz
+        }
+      `),
     )
 
     expect(
@@ -62,7 +75,15 @@ describe('mergeQueries function', function () {
           `,
         ),
       ),
-    ).to.equalIgnoreSpaces('{ foo bar baz }')
+    ).to.equal(
+      print(gql`
+        {
+          foo
+          bar
+          baz
+        }
+      `),
+    )
 
     expect(
       print(
@@ -79,7 +100,14 @@ describe('mergeQueries function', function () {
           `,
         ),
       ),
-    ).to.equalIgnoreSpaces('{ foo bar }')
+    ).to.equal(
+      print(gql`
+        {
+          foo
+          bar
+        }
+      `),
+    )
   })
 
   it('throws an error when passed invalid params', function () {
diff --git a/core/base-service/loader.spec.js b/core/base-service/loader.spec.js
index 9990ef591583f330cdd3cdb560283736181b19ab..5973acf4d766b8e40b71bd841e027b74458fb3f5 100644
--- a/core/base-service/loader.spec.js
+++ b/core/base-service/loader.spec.js
@@ -1,15 +1,14 @@
 import path from 'path'
 import { fileURLToPath } from 'url'
-import chai from 'chai'
+import { expect, use } from 'chai'
 import chaiAsPromised from 'chai-as-promised'
 import {
   loadServiceClasses,
   getServicePaths,
   InvalidService,
 } from './loader.js'
-chai.use(chaiAsPromised)
+use(chaiAsPromised)
 
-const { expect } = chai
 const fixturesDir = path.join(
   path.dirname(fileURLToPath(import.meta.url)),
   'loader-test-fixtures',
diff --git a/core/base-service/openapi.spec.js b/core/base-service/openapi.spec.js
index aa56fb7a6196d1674807224ca1549d0b380be010..7700125ba975ba5bccda1051d020ff01ec7243f3 100644
--- a/core/base-service/openapi.spec.js
+++ b/core/base-service/openapi.spec.js
@@ -1,4 +1,4 @@
-import chai from 'chai'
+import { expect } from 'chai'
 import {
   category2openapi,
   pathParam,
@@ -7,7 +7,6 @@ import {
   queryParams,
 } from './openapi.js'
 import BaseJsonService from './base-json.js'
-const { expect } = chai
 
 class OpenApiService extends BaseJsonService {
   static category = 'build'
diff --git a/core/register-chai-plugins.spec.js b/core/register-chai-plugins.spec.js
index 7b38803d7b8d0faf105f608d86d0b229167f7745..8ca325781b6faedfb253db023ebfd4d8927b53ea 100644
--- a/core/register-chai-plugins.spec.js
+++ b/core/register-chai-plugins.spec.js
@@ -1,5 +1,3 @@
 import { use } from 'chai'
-import chaiString from 'chai-string'
 import sinonChai from 'sinon-chai'
-use(chaiString)
 use(sinonChai)
diff --git a/package-lock.json b/package-lock.json
index 95387072e70d94a262561f3a3b9cd028fb1be2d0..8cde36083b2404dbf5a54f7a2a3aeecc124b9deb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -66,10 +66,9 @@
         "@typescript-eslint/parser": "^8.17.0",
         "c8": "^10.1.2",
         "caller": "^1.1.0",
-        "chai": "^4.5.0",
+        "chai": "5.1.2",
         "chai-as-promised": "^8.0.1",
         "chai-datetime": "^1.8.1",
-        "chai-string": "^1.4.0",
         "child-process-promise": "^2.2.1",
         "clsx": "^2.1.1",
         "concurrently": "^9.1.0",
@@ -122,7 +121,7 @@
         "sazerac": "^2.0.0",
         "simple-git-hooks": "^2.11.1",
         "sinon": "^19.0.2",
-        "sinon-chai": "^3.7.0",
+        "sinon-chai": "4.0.0",
         "snap-shot-it": "^7.9.10",
         "start-server-and-test": "2.0.8",
         "tsd": "^0.31.2",
@@ -7468,11 +7467,11 @@
       }
     },
     "node_modules/assertion-error": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
-      "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+      "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
       "engines": {
-        "node": "*"
+        "node": ">=12"
       }
     },
     "node_modules/astral-regex": {
@@ -8482,20 +8481,18 @@
       }
     },
     "node_modules/chai": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz",
-      "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==",
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz",
+      "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==",
       "dependencies": {
-        "assertion-error": "^1.1.0",
-        "check-error": "^1.0.3",
-        "deep-eql": "^4.1.3",
-        "get-func-name": "^2.0.2",
-        "loupe": "^2.3.6",
-        "pathval": "^1.1.1",
-        "type-detect": "^4.1.0"
+        "assertion-error": "^2.0.1",
+        "check-error": "^2.1.1",
+        "deep-eql": "^5.0.1",
+        "loupe": "^3.1.0",
+        "pathval": "^2.0.0"
       },
       "engines": {
-        "node": ">=4"
+        "node": ">=12"
       }
     },
     "node_modules/chai-as-promised": {
@@ -8510,15 +8507,6 @@
         "chai": ">= 2.1.2 < 6"
       }
     },
-    "node_modules/chai-as-promised/node_modules/check-error": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
-      "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
-      "dev": true,
-      "engines": {
-        "node": ">= 16"
-      }
-    },
     "node_modules/chai-datetime": {
       "version": "1.8.1",
       "resolved": "https://registry.npmjs.org/chai-datetime/-/chai-datetime-1.8.1.tgz",
@@ -8528,15 +8516,6 @@
         "chai": ">1.9.0"
       }
     },
-    "node_modules/chai-string": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/chai-string/-/chai-string-1.5.0.tgz",
-      "integrity": "sha512-sydDC3S3pNAQMYwJrs6dQX0oBQ6KfIPuOZ78n7rocW0eJJlsHPh2t3kwW7xfwYA/1Bf6/arGtSUo16rxR2JFlw==",
-      "dev": true,
-      "peerDependencies": {
-        "chai": "^4.1.2"
-      }
-    },
     "node_modules/chai-subset": {
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/chai-subset/-/chai-subset-1.6.0.tgz",
@@ -8552,12 +8531,12 @@
       "integrity": "sha512-6ns0SU21xdRCoEXVKH3HGbwnsgfVMXQ+sU5V8PI9rfxaITos8lss1vUxbF1FAcJKjfqmmmLVlr/z3sLes00w+A==",
       "dev": true
     },
-    "node_modules/chai/node_modules/type-detect": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz",
-      "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==",
+    "node_modules/chai/node_modules/deep-eql": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
+      "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
       "engines": {
-        "node": ">=4"
+        "node": ">=6"
       }
     },
     "node_modules/chalk": {
@@ -8647,14 +8626,11 @@
       }
     },
     "node_modules/check-error": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
-      "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
-      "dependencies": {
-        "get-func-name": "^2.0.2"
-      },
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
+      "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
       "engines": {
-        "node": "*"
+        "node": ">= 16"
       }
     },
     "node_modules/check-more-types": {
@@ -10667,6 +10643,7 @@
       "version": "4.1.3",
       "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
       "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
+      "dev": true,
       "dependencies": {
         "type-detect": "^4.0.0"
       },
@@ -14307,6 +14284,7 @@
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
       "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
+      "dev": true,
       "engines": {
         "node": "*"
       }
@@ -15679,6 +15657,33 @@
         "url": "https://github.com/chalk/ansi-styles?sponsor=1"
       }
     },
+    "node_modules/icedfrisby/node_modules/assertion-error": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
+      "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/icedfrisby/node_modules/chai": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz",
+      "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==",
+      "dev": true,
+      "dependencies": {
+        "assertion-error": "^1.1.0",
+        "check-error": "^1.0.3",
+        "deep-eql": "^4.1.3",
+        "get-func-name": "^2.0.2",
+        "loupe": "^2.3.6",
+        "pathval": "^1.1.1",
+        "type-detect": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/icedfrisby/node_modules/chalk": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -15695,6 +15700,18 @@
         "url": "https://github.com/chalk/chalk?sponsor=1"
       }
     },
+    "node_modules/icedfrisby/node_modules/check-error": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
+      "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
+      "dev": true,
+      "dependencies": {
+        "get-func-name": "^2.0.2"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
     "node_modules/icedfrisby/node_modules/color-convert": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -15713,6 +15730,24 @@
       "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
       "dev": true
     },
+    "node_modules/icedfrisby/node_modules/loupe": {
+      "version": "2.3.7",
+      "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz",
+      "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==",
+      "dev": true,
+      "dependencies": {
+        "get-func-name": "^2.0.1"
+      }
+    },
+    "node_modules/icedfrisby/node_modules/pathval": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
+      "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
     "node_modules/icedfrisby/node_modules/supports-color": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -15725,6 +15760,15 @@
         "node": ">=8"
       }
     },
+    "node_modules/icedfrisby/node_modules/type-detect": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz",
+      "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/iconv-lite": {
       "version": "0.6.3",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@@ -18510,12 +18554,9 @@
       }
     },
     "node_modules/loupe": {
-      "version": "2.3.6",
-      "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz",
-      "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==",
-      "dependencies": {
-        "get-func-name": "^2.0.0"
-      }
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz",
+      "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg=="
     },
     "node_modules/lower-case": {
       "version": "2.0.2",
@@ -23427,11 +23468,11 @@
       }
     },
     "node_modules/pathval": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
-      "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz",
+      "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==",
       "engines": {
-        "node": "*"
+        "node": ">= 14.16"
       }
     },
     "node_modules/pause-stream": {
@@ -27488,12 +27529,12 @@
       }
     },
     "node_modules/sinon-chai": {
-      "version": "3.7.0",
-      "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz",
-      "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-4.0.0.tgz",
+      "integrity": "sha512-cWqO7O2I4XfJDWyWElAQ9D/dtdh5Mo0RHndsfiiYyjWnlPzBJdIvjCVURO4EjyYaC3BjV+ISNXCfTXPXTEIEWA==",
       "dev": true,
       "peerDependencies": {
-        "chai": "^4.0.0",
+        "chai": "^5.0.0",
         "sinon": ">=4.0.0"
       }
     },
@@ -29554,6 +29595,7 @@
       "version": "4.0.8",
       "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
       "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+      "dev": true,
       "engines": {
         "node": ">=4"
       }
diff --git a/package.json b/package.json
index 7bd03e68112bac99aa5f1682fcef62424ef6b13a..edf4051d2f5152183afecafaf92184757899f0b9 100644
--- a/package.json
+++ b/package.json
@@ -153,10 +153,9 @@
     "@typescript-eslint/parser": "^8.17.0",
     "c8": "^10.1.2",
     "caller": "^1.1.0",
-    "chai": "^4.5.0",
+    "chai": "5.1.2",
     "chai-as-promised": "^8.0.1",
     "chai-datetime": "^1.8.1",
-    "chai-string": "^1.4.0",
     "child-process-promise": "^2.2.1",
     "clsx": "^2.1.1",
     "concurrently": "^9.1.0",
@@ -209,7 +208,7 @@
     "sazerac": "^2.0.0",
     "simple-git-hooks": "^2.11.1",
     "sinon": "^19.0.2",
-    "sinon-chai": "^3.7.0",
+    "sinon-chai": "4.0.0",
     "snap-shot-it": "^7.9.10",
     "start-server-and-test": "2.0.8",
     "tsd": "^0.31.2",
diff --git a/services/dynamic/json-path.spec.js b/services/dynamic/json-path.spec.js
index 6879f735950c3eab51f30378a480fab393926518..b67e4c5b061a48503ba06339056a3c0ac245e7a3 100644
--- a/services/dynamic/json-path.spec.js
+++ b/services/dynamic/json-path.spec.js
@@ -1,8 +1,7 @@
-import chai from 'chai'
+import { expect, use } from 'chai'
 import chaiAsPromised from 'chai-as-promised'
 import jsonPath from './json-path.js'
-const { expect } = chai
-chai.use(chaiAsPromised)
+use(chaiAsPromised)
 
 describe('JSON Path service factory', function () {
   describe('fetch()', function () {
diff --git a/services/github/auth/acceptor.spec.js b/services/github/auth/acceptor.spec.js
index e9d11895a52870ec43a7492a4afe1308f12e7858..e100cb2cc1825aa94d5a8efad9144f0a3a4dac42 100644
--- a/services/github/auth/acceptor.spec.js
+++ b/services/github/auth/acceptor.spec.js
@@ -114,10 +114,11 @@ describe('Github token acceptor', function () {
         const res = await got.post(`${baseUrl}/github-auth/done`, {
           body: form,
         })
-        expect(res.body).to.startWith(
-          '<p>Shields.io has received your app-specific GitHub user token.',
-        )
-
+        expect(
+          res.body.startsWith(
+            '<p>Shields.io has received your app-specific GitHub user token.',
+          ),
+        ).to.be.true
         expect(onTokenAccepted).to.have.been.calledWith(fakeAccessToken)
       })
     })
diff --git a/services/packagist/packagist-dependency-version.spec.js b/services/packagist/packagist-dependency-version.spec.js
index 1ceb589825f806aaf87d099a4ab74f9a17db1b45..1f1cde2eafccffa0772106a02bb52bb0c243ebe9 100644
--- a/services/packagist/packagist-dependency-version.spec.js
+++ b/services/packagist/packagist-dependency-version.spec.js
@@ -1,8 +1,7 @@
-import chai from 'chai'
+import { expect, use } from 'chai'
 import chaiAsPromised from 'chai-as-promised'
 import PackagistDependencyVersion from './packagist-dependency-version.service.js'
-const { expect } = chai
-chai.use(chaiAsPromised)
+use(chaiAsPromised)
 
 describe('PackagistDependencyVersion', function () {
   const fullPackagistJson = {