diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Revision history for nonempty-vector
 
+## 0.2.2.0
+
+* Drop support for GHC<8.10, update CI, bump bounds for `primitive`.
+* Added `partitionWith` from `vector`. [(#11)](https://github.com/emilypi/nonempty-vector/pull/11) - Thanks @AlistairB!
+
 ## 0.2.1.0
 
 * Added `consV` and `snocV` primitives for consing a vector to create a nonempty one. [(#8)](https://github.com/emilypi/nonempty-vector/pull/8) - Thanks @AlistairB!
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # Non-empty Vectors
 
-[![Build Status](https://travis-ci.org/emilypi/nonempty-vector.svg?branch=master)](https://travis-ci.org/emilypi/nonempty-vector) [![Hackage](https://img.shields.io/hackage/v/nonempty-vector.svg)](https://hackage.haskell.org/package/nonempty-vector)
+![Build Status](https://github.com/emilypi/nonempty-vector/workflows/CI/badge.svg) [![Hackage](https://img.shields.io/hackage/v/nonempty-vector.svg)](https://hackage.haskell.org/package/nonempty-vector)
 
 This package presents thin wrappers around mutable and immutable [Data.Vector](https://hackage.haskell.org/package/vector) types. The entire Vector API is supported for both sets of boxed vectors, with future plans to support unboxed, primitive, storable, and generic vectors.
 
diff --git a/Setup.hs b/Setup.hs
deleted file mode 100644
--- a/Setup.hs
+++ /dev/null
@@ -1,6 +0,0 @@
-module Main where
-
-import Distribution.Extra.Doctest (defaultMainWithDoctests)
-
-main :: IO ()
-main = defaultMainWithDoctests "doctests"
diff --git a/nonempty-vector.cabal b/nonempty-vector.cabal
--- a/nonempty-vector.cabal
+++ b/nonempty-vector.cabal
@@ -1,40 +1,31 @@
-cabal-version:   1.24
+cabal-version:   3.0
 name:            nonempty-vector
-version:         0.2.1.0
+version:         0.2.2.0
 synopsis:        Non-empty vectors
 description:     Performant, non-empty mutable and immutable vectors
 homepage:        https://github.com/emilypi/nonempty-vector
 bug-reports:     https://github.com/emilypi/nonempty-vector/issues
-license:         BSD3
+license:         BSD-3-Clause
 license-file:    LICENSE
 author:          Emily Pillmore
 maintainer:      emilypi@cohomolo.gy
-copyright:       (c) 2019-2020 Emily Pillmore <emilypi@cohomolo.gy>
+copyright:       (c) 2019-2023 Emily Pillmore <emilypi@cohomolo.gy>
 category:        Data
-build-type:      Custom
+build-type:      Simple
 extra-doc-files:
   CHANGELOG.md
   README.md
 
 tested-with:
-  GHC ==8.0.2
-   || ==8.4.3
-   || ==8.4.4
-   || ==8.6.3
-   || ==8.6.5
-   || ==8.8.1
-   || ==8.10.2
+  GHC ==8.10.7
+   || ==9.0.2
+   || ==9.2.6
+   || ==9.4.4
 
 source-repository head
   type:     git
   location: https://github.com/emilypi/nonempty-vector.git
 
-custom-setup
-  setup-depends:
-      base           >=4.9 && <5
-    , Cabal
-    , cabal-doctest
-
 library
   exposed-modules:
     Data.Vector.NonEmpty
@@ -42,23 +33,26 @@
     Data.Vector.NonEmpty.Mutable
 
   build-depends:
-      base       >=4.9  && <5
+      base       >=4.14  && <5
     , deepseq
-    , primitive  >=0.6  && <0.8
-    , vector     >=0.12 && <0.13
+    , primitive  >=0.6  && <0.9
+    , vector     >=0.12 && <0.14
 
   hs-source-dirs:   src
   default-language: Haskell2010
   ghc-options:      -Wall
 
-test-suite doctests
+test-suite tasty
   default-language:  Haskell2010
   type:              exitcode-stdio-1.0
-  main-is:           doctests.hs
+  main-is:           Main.hs
   build-depends:
-      base     >=4.9 && <5
-    , doctest
+      base     >=4.14 && <5
+    , nonempty-vector
+    , QuickCheck
+    , tasty
+    , tasty-quickcheck
+    , vector
 
   hs-source-dirs:    test
   ghc-options:       -Wall -threaded
-  x-doctest-options: --fast
diff --git a/src/Data/Vector/NonEmpty.hs b/src/Data/Vector/NonEmpty.hs
--- a/src/Data/Vector/NonEmpty.hs
+++ b/src/Data/Vector/NonEmpty.hs
@@ -153,7 +153,7 @@
 , takeWhile, dropWhile
 
   -- * Partitioning
-, partition, unstablePartition, span, break
+, partition, partitionWith, unstablePartition, span, break
 
   -- * Searching
 , elem, notElem, find, findIndex, findIndices, elemIndex
@@ -191,6 +191,7 @@
 import Control.Monad.ST
 
 import qualified Data.Foldable as Foldable
+import Data.Either (Either(..))
 import Data.Functor
 import Data.Int
 import Data.List.NonEmpty (NonEmpty(..))
@@ -206,7 +207,7 @@
 
 
 -- $setup
--- >>> import Prelude (Int, String, ($), (.), (+), (<), const, return)
+-- >>> import Prelude (Int, String, ($), (.), (+), (<), const, return, Maybe(..), Either(..))
 -- >>> import Data.Bool
 -- >>> import Data.Eq
 -- >>> import qualified Prelude as P
@@ -2110,6 +2111,20 @@
 partition :: (a -> Bool) -> NonEmptyVector a -> (Vector a, Vector a)
 partition f = V.partition f . _neVec
 {-# INLINE partition #-}
+
+-- | /O(n)/ Split the non-empty vector in two parts, the first one
+-- containing the Left elements and the second containing the
+-- Right elements. The relative order of the elements is preserved.
+--
+-- If all elements produce a Left (or Right), one of the
+-- resulting vectors may be empty.
+--
+-- >>> partitionWith (\a -> if a < 3 then Left a else Right (P.show a)) (unsafeFromList [1..5])
+-- ([1,2],["3","4","5"])
+--
+partitionWith :: (a -> Either b c) -> NonEmptyVector a -> (Vector b, Vector c)
+partitionWith f = V.partitionWith f . _neVec
+{-# INLINE partitionWith #-}
 
 -- | /O(n)/ Split the non-empty vector in two parts, the first one
 -- containing those elements that satisfy the predicate and the second
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+-- |
+-- Module       : Main (tests)
+-- Copyright 	: 2019-2023 (c) Emily Pillmore
+-- License	: BSD
+--
+-- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy>
+-- Stability	: Experimental
+-- Portability	: TypeFamilies
+--
+module Main
+( main
+) where
+
+
+import Data.Maybe
+import Data.Vector (Vector)
+import Data.Vector.NonEmpty (NonEmptyVector)
+import qualified Data.Vector.NonEmpty as NEV
+
+import Test.QuickCheck
+import Test.Tasty
+import Test.Tasty.QuickCheck
+
+main :: IO ()
+main = defaultMain $ testGroup "NonEmptyVector constructor"
+    [ testProperty "prop_reverse" prop_reverse
+    , testProperty "prop_from_to_list" prop_from_to_list
+    , testProperty "prop_from_to_vec" prop_from_to_vec
+    ]
+
+genList :: Gen [Int]
+genList = listOf1 (choose (1, 100))
+
+genNEV :: Gen (NonEmptyVector Int)
+genNEV = fmap (fromJust . NEV.fromList) genList
+
+genV :: Gen (Vector Int)
+genV = NEV.toVector <$> genNEV
+
+prop_reverse :: Property
+prop_reverse =  forAll genNEV $ \t ->
+  NEV.reverse (NEV.reverse t) == t
+
+prop_from_to_list :: Property
+prop_from_to_list =
+  forAll genNEV $ \t ->
+  forAll genList $ \u ->
+    NEV.fromList (NEV.toList t) == Just t
+      && fmap NEV.toList (NEV.fromList u) == Just u
+
+prop_from_to_vec :: Property
+prop_from_to_vec =
+  forAll genNEV $ \t ->
+  forAll genV $ \u ->
+    NEV.fromVector (NEV.toVector t) == Just t
+      && (NEV.toVector <$> NEV.fromVector u) == Just u
diff --git a/test/doctests.hs b/test/doctests.hs
deleted file mode 100644
--- a/test/doctests.hs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Main where
-
-import Build_doctests (flags, pkgs, module_sources)
-import Test.DocTest (doctest)
-
-main :: IO ()
-main = doctest $ flags ++ pkgs ++ module_sources
