diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,41 @@
 # Revision history for greskell
 
+## 1.0.1.0  -- 2020-04-24
+
+### GTraversal module
+
+* Add the following functions.
+  * `gRepeat`
+  * `gTimes`
+  * `gUntilHead`
+  * `gUntilTail`
+  * `gEmitHead`
+  * `gEmitTail`
+  * `gEmitHeadT`
+  * `gEmitTailT`
+  * `gLoops`
+  * `gIs`
+  * `gIs'`
+  * `gIsP`
+  * `gIsP'`
+  * `gCyclicPath`
+  * `gCyclicPath'`
+  * `gSimplePath`
+  * `gSimplePath'`
+  * `gUnion`
+  * `gChoose3`
+  * `gConstant`
+  * `gLocal`
+  * `gBarrier`
+  * `gDedup`
+  * `gDedupN`
+  * `gUnfold`
+* Add the follwing types.
+  * `RepeatUntil`
+  * `RepeatEmit`
+  * `RepeatPos`
+  * `RepeatLabel`
+
 ## 1.0.0.1  -- 2019-12-30
 
 * Confirm test with `base-4.13.0.0`
diff --git a/greskell.cabal b/greskell.cabal
--- a/greskell.cabal
+++ b/greskell.cabal
@@ -1,5 +1,5 @@
 name:                   greskell
-version:                1.0.0.1
+version:                1.0.1.0
 author:                 Toshio Ito <debug.ito@gmail.com>
 maintainer:             Toshio Ito <debug.ito@gmail.com>
 license:                BSD3
@@ -26,7 +26,7 @@
   -- default-extensions:   
   other-extensions:     OverloadedStrings, GeneralizedNewtypeDeriving,
                         FlexibleInstances, FlexibleContexts, MultiParamTypeClasses, TypeFamilies,
-                        GADTs, DeriveTraversable, DeriveGeneric
+                        GADTs, DeriveTraversable, DeriveGeneric, StandaloneDeriving
   exposed-modules:      Data.Greskell,
                         Data.Greskell.Gremlin,
                         Data.Greskell.Binder,
diff --git a/src/Data/Greskell/GTraversal.hs b/src/Data/Greskell/GTraversal.hs
--- a/src/Data/Greskell/GTraversal.hs
+++ b/src/Data/Greskell/GTraversal.hs
@@ -1,4 +1,5 @@
-{-# LANGUAGE OverloadedStrings, FlexibleInstances, FlexibleContexts, MultiParamTypeClasses, TypeFamilies, GADTs #-}
+{-# LANGUAGE OverloadedStrings, FlexibleInstances, FlexibleContexts, MultiParamTypeClasses,
+    TypeFamilies, GADTs, GeneralizedNewtypeDeriving, StandaloneDeriving #-}
 {-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
 -- |
 -- Module: Data.Greskell.GTraversal
@@ -57,6 +58,15 @@
          gIdentity,
          gIdentity',
          gFilter,
+         gCyclicPath,
+         gCyclicPath',
+         gSimplePath,
+         gSimplePath',
+         -- ** Is step
+         gIs,
+         gIs',
+         gIsP,
+         gIsP',
          -- ** Has steps
          gHas1,
          gHas1',
@@ -91,10 +101,34 @@
          gLimit,
          gTail,
          gSkip,
+         -- ** Repeat step
+         gRepeat,
+         gTimes,
+         gUntilHead,
+         gUntilTail,
+         gEmitHead,
+         gEmitTail,
+         gEmitHeadT,
+         gEmitTailT,
+         gLoops,
+         RepeatUntil(..),
+         RepeatEmit(..),
+         RepeatPos(..),
+         RepeatLabel(..),
+         -- ** Branching steps
+         gLocal,
+         gUnion,
+         gChoose3,
+         -- ** Barrier steps
+         gBarrier,
+         gDedup,
+         gDedupN,
          -- ** Transformation steps
          gFlatMap,
          gV,
          gV',
+         gConstant,
+         gUnfold,
          -- ** As step
          gAs,
          -- ** Accessor steps
@@ -175,6 +209,7 @@
     T, Key, Cardinality,
     KeyValue(..), Keys(..)
   )
+import qualified Data.Greskell.Greskell as Greskell
 import Data.Greskell.GraphSON (GValue, FromGraphSON)
 import Data.Greskell.Gremlin
   ( Comparator(..),
@@ -553,6 +588,60 @@
 gFilter :: (ToGTraversal g, WalkType c, WalkType p, Split c p) => g c s e -> Walk p s s
 gFilter walk = unsafeWalk "filter" [travToG walk]
 
+-- | @.cyclicPath@ step.
+--
+-- @since 1.0.1.0
+gCyclicPath :: (WalkType c) => Walk c a a
+gCyclicPath = liftWalk gCyclicPath'
+
+-- | Monomorphic version of 'gCyclicPath'.
+--
+-- @since 1.0.1.0
+gCyclicPath' :: Walk Filter a a
+gCyclicPath' = unsafeWalk "cyclicPath" []
+
+-- | @.simplePath@ step.
+--
+-- @since 1.0.1.0
+gSimplePath :: (WalkType c) => Walk c a a
+gSimplePath = liftWalk gSimplePath'
+
+-- | Monomorphic version of 'gSimplePath'.
+--
+-- @since 1.0.1.0
+gSimplePath' :: Walk Filter a a
+gSimplePath' = unsafeWalk "simplePath" []
+
+-- | @.is@ step of simple equality.
+--
+-- >>> toGremlin (source "g" & sV' [] &. gValues ["age" :: Key AVertex Int] &. gIs 30)
+-- "g.V().values(\"age\").is(30)"
+--
+-- @since 1.0.1.0
+gIs :: (WalkType c) => Greskell v -> Walk c v v
+gIs = liftWalk . gIs'
+
+-- | Monomorphic version of 'gIs'.
+--
+-- @since 1.0.1.0
+gIs' :: Greskell v -> Walk Filter v v
+gIs' v = unsafeWalk "is" [toGremlin v]
+
+-- | @.is@ step with predicate 'P'.
+--
+-- >>> toGremlin (source "g" & sV' [] &. gValues ["age" :: Key AVertex Int] &. gIsP (pLte 30))
+-- "g.V().values(\"age\").is(P.lte(30))"
+--
+-- @since 1.0.1.0
+gIsP :: (WalkType c) => Greskell (P v) -> Walk c v v
+gIsP = liftWalk . gIsP'
+
+-- | Monomorphic version of 'gIsP'.
+--
+-- @since 1.0.1.0
+gIsP' :: Greskell (P v) -> Walk Filter v v
+gIsP' p = unsafeWalk "is" [toGremlin p]
+
 -- | @.has@ step with one argument.
 --
 -- >>> toGremlin (source "g" & sV' [] &. gHas1 "age")
@@ -748,7 +837,289 @@
 gSkip :: Greskell Int -> Walk Transform s s
 gSkip num = unsafeWalk "skip" [toGremlin num]
 
+-- | A label that points to a loop created by @.repeat@ step. It can
+-- be used by @.loops@ step to specify the loop.
+--
+-- @since 1.0.1.0
+newtype RepeatLabel =
+  RepeatLabel { unRepeatLabel :: Text }
+  deriving (Show,Eq,Ord,IsString)
 
+-- | Return Gremlin String literal.
+instance ToGreskell RepeatLabel where
+  type GreskellReturn RepeatLabel = Text
+  toGreskell (RepeatLabel t) = Greskell.string t
+
+-- | Position of a step modulator relative to @.repeat@ step.
+--
+-- @since 1.0.1.0
+data RepeatPos = RepeatHead -- ^ Modulator before the @.repeat@ step.
+               | RepeatTail -- ^ Modulator after the @.repeat@ step.
+               deriving (Show,Eq,Ord,Enum,Bounded)
+
+-- | @.until@ or @.times@ modulator step.
+--
+-- Type @c@ is the 'WalkType' of the parent @.repeat@ step. Type @s@
+-- is the start (and end) type of the @.repeat@ step.
+--
+-- @since 1.0.1.0
+data RepeatUntil c s where
+  -- | @.times@ modulator.
+  RepeatTimes :: Greskell Int -> RepeatUntil c s
+  -- | @.until@ modulator with a sub-traversal as the predicate to
+  -- decide if the repetition should stop.
+  RepeatUntilT :: (WalkType cc, WalkType c, Split cc c) => GTraversal cc s e -> RepeatUntil c s
+
+deriving instance Show (RepeatUntil c s)
+
+makeUntilWalk :: WalkType c => RepeatUntil c s -> Walk c s s
+makeUntilWalk (RepeatTimes count) = unsafeWalk "times" [toGremlin count]
+makeUntilWalk (RepeatUntilT trav) = unsafeWalk "until" [toGremlin trav]
+
+-- | @.emit@ modulator step.
+--
+-- Type @c@ is the 'WalkType' of the parent @.repeat@ step. Type @s@
+-- is the start (and end) type of the @.repeat@ step.
+--
+-- @since 1.0.1.0
+data RepeatEmit c s where
+  -- | @.emit@ modulator without argument. It always emits the input
+  -- traverser of type @s@.
+  RepeatEmit :: RepeatEmit c s
+  -- | @.emit@ modulator with a sub-traversal as the predicate to
+  -- decide if it emits the traverser.
+  RepeatEmitT :: (WalkType cc, WalkType c, Split cc c) => GTraversal cc s e -> RepeatEmit c s
+
+deriving instance Show (RepeatEmit c s)
+
+makeEmitWalk :: WalkType c => RepeatEmit c s -> Walk c s s
+makeEmitWalk (RepeatEmit) = unsafeWalk "emit" []
+makeEmitWalk (RepeatEmitT trav) = unsafeWalk "emit" [toGremlin trav]
+
+
+
+-- | Zero or more Gremlin steps.
+--
+-- @since 1.0.1.0
+newtype MWalk c s e = MWalk (Maybe (Walk c s e))
+                    deriving (Show)
+
+deriving instance WalkType c => Semigroup (MWalk c s s)
+deriving instance WalkType c => Monoid (MWalk c s s)
+
+toMWalk :: Walk c s e -> MWalk c s e
+toMWalk = MWalk . Just
+
+-- | @MWalk Nothing@ is coverted to identity step.
+fromMWalk :: WalkType c => MWalk c s s -> Walk c s s
+fromMWalk (MWalk Nothing) = mempty
+fromMWalk (MWalk (Just w)) = w
+
+
+
+-- | @.repeat@ step.
+--
+-- @since 1.0.1.0
+gRepeat :: (ToGTraversal g, WalkType c)
+        => Maybe RepeatLabel -- ^ Label for the loop.
+        -> Maybe (RepeatPos, RepeatUntil c s)
+        -- ^ @.until@ or @.times@ modulator. You can use 'gTimes',
+        -- 'gUntilHead', 'gUntilTail' to make this argument.
+        -> Maybe (RepeatPos, RepeatEmit c s)
+        -- ^ @.emit@ modulator. You can use 'gEmitHead', 'gEmitTail',
+        -- 'gEmitHeadT', 'gEmitTailT' to make this argument.
+        -> g c s s -- ^ Repeated traversal
+        -> Walk c s s
+gRepeat mlabel muntil memit repeated_trav = fromMWalk (head_walk <> toMWalk repeat_body <> tail_walk)
+  where
+    repeat_body = unsafeWalk "repeat" (label_args ++ [toGremlin $ toGTraversal repeated_trav])
+    label_args = maybe [] (\l -> [toGremlin l]) mlabel
+    head_walk = head_until <> head_emit
+    tail_walk = tail_until <> tail_emit
+    (head_until, tail_until) =
+      case muntil of
+        Nothing -> (mempty, mempty)
+        Just (pos, u) ->
+          case pos of
+            RepeatHead -> (toMWalk $ makeUntilWalk u, mempty)
+            RepeatTail -> (mempty, toMWalk $ makeUntilWalk u)
+    (head_emit, tail_emit) =
+      case memit of
+        Nothing -> (mempty, mempty)
+        Just (pos, e) ->
+          case pos of
+            RepeatHead -> (toMWalk $ makeEmitWalk e, mempty)
+            RepeatTail -> (mempty, toMWalk $ makeEmitWalk e)
+
+-- | @.times@ modulator before the @.repeat@ step. It always returns
+-- 'Just'.
+--
+-- >>> toGremlin (source "g" & sV' [] &. gRepeat Nothing (gTimes 3) Nothing (gOut' []))
+-- "g.V().times(3).repeat(__.out())"
+--
+-- @since 1.0.1.0
+gTimes :: Greskell Int
+       -- ^ Repeat count. If it's less than or equal to 0, the
+       -- repeated traversal is never executed.
+       -> Maybe (RepeatPos, RepeatUntil c s)
+gTimes c = Just (RepeatHead, RepeatTimes c)
+
+-- | @.until@ modulator before the @.repeat@ step. It always returns
+-- 'Just'.
+--
+-- >>> toGremlin (source "g" & sV' [] &. gRepeat Nothing (gUntilHead $ gHasLabel' "person") Nothing (gOut' []))
+-- "g.V().until(__.hasLabel(\"person\")).repeat(__.out())"
+--
+-- @since 1.0.1.0
+gUntilHead :: (ToGTraversal g, WalkType c, WalkType cc, Split cc c) => g cc s e -> Maybe (RepeatPos, RepeatUntil c s)
+gUntilHead trav = Just (RepeatHead, RepeatUntilT $ toGTraversal trav)
+
+-- | @.until@ modulator after the @.repeat@ step. It always returns
+-- 'Just'.
+--
+-- >>> toGremlin (source "g" & sV' [] &. gRepeat Nothing (gUntilTail $ gHasLabel' "person") Nothing (gOut' []))
+-- "g.V().repeat(__.out()).until(__.hasLabel(\"person\"))"
+--
+-- @since 1.0.1.0
+gUntilTail :: (ToGTraversal g, WalkType c, WalkType cc, Split cc c) => g cc s e -> Maybe (RepeatPos, RepeatUntil c s)
+gUntilTail trav = Just (RepeatTail, RepeatUntilT $ toGTraversal trav)
+
+-- | @.emit@ modulator without argument before the @.repeat@ step. It
+-- always returns 'Just'.
+--
+-- >>> toGremlin (source "g" & sV' [] &. gRepeat Nothing Nothing gEmitHead (gOut' []))
+-- "g.V().emit().repeat(__.out())"
+--
+-- @since 1.0.1.0
+gEmitHead :: Maybe (RepeatPos, RepeatEmit c s)
+gEmitHead = Just (RepeatHead, RepeatEmit)
+
+-- | @.emit@ modulator without argument after the @.repeat@ step. It
+-- always returns 'Just'.
+--
+-- >>> toGremlin (source "g" & sV' [] &. gRepeat Nothing Nothing gEmitTail (gOut' []))
+-- "g.V().repeat(__.out()).emit()"
+--
+-- @since 1.0.1.0
+gEmitTail :: Maybe (RepeatPos, RepeatEmit c s)
+gEmitTail = Just (RepeatTail, RepeatEmit)
+
+-- | @.emit@ modulator with a sub-traversal argument before the
+-- @.repeat@ step. It always returns 'Just'.
+--
+-- >>> toGremlin (source "g" & sV' [] &. gRepeat Nothing Nothing (gEmitHeadT $ gHasLabel' "person") (gOut' []))
+-- "g.V().emit(__.hasLabel(\"person\")).repeat(__.out())"
+--
+-- @since 1.0.1.0
+gEmitHeadT :: (ToGTraversal g, WalkType c, WalkType cc, Split cc c) => g cc s e -> Maybe (RepeatPos, RepeatEmit c s)
+gEmitHeadT trav = Just (RepeatHead, RepeatEmitT $ toGTraversal trav)
+
+-- | @.emit@ modulator with a sub-traversal argument after the
+-- @.repeat@ step. It always returns 'Just'.
+--
+-- >>> toGremlin (source "g" & sV' [] &. gRepeat Nothing Nothing (gEmitTailT $ gHasLabel' "person") (gOut' []))
+-- "g.V().repeat(__.out()).emit(__.hasLabel(\"person\"))"
+--
+-- @since 1.0.1.0
+gEmitTailT :: (ToGTraversal g, WalkType c, WalkType cc, Split cc c) => g cc s e -> Maybe (RepeatPos, RepeatEmit c s)
+gEmitTailT trav = Just (RepeatTail, RepeatEmitT $ toGTraversal trav)
+
+-- | @.loops@ step.
+--
+-- >>> let loop_label = Just "the_loop"
+-- >>> toGremlin (source "g" & sV' [] &. gRepeat loop_label (gUntilTail $ gLoops loop_label >>> gIs 3) Nothing (gOut' []))
+-- "g.V().repeat(\"the_loop\",__.out()).until(__.loops(\"the_loop\").is(3))"
+--
+-- @since 1.0.1.0
+gLoops :: Maybe RepeatLabel -> Walk Transform s Int
+gLoops mlabel = unsafeWalk "loops" $ maybe [] (\l -> [toGremlin l]) mlabel
+
+-- | @.local@ step.
+--
+-- >>> toGremlin (source "g" & sV' [] &. gLocal ( gOut' [] >>> gLimit 3 ))
+-- "g.V().local(__.out().limit(3))"
+--
+-- @since 1.0.1.0
+gLocal :: (ToGTraversal g, WalkType c) => g c s e -> Walk c s e
+gLocal t = unsafeWalk "local" [toGremlin $ toGTraversal t]
+
+-- | @.union@ step.
+--
+-- >>> let key_age = ("age" :: Key AVertex Int)
+-- >>> let key_birth_year = ("birth_year" :: Key AVertex Int)
+-- >>> toGremlin (source "g" & sV' [] &. gUnion [gValues [key_age], gValues [key_birth_year]])
+-- "g.V().union(__.values(\"age\"),__.values(\"birth_year\"))"
+--
+-- @since 1.0.1.0
+gUnion :: (ToGTraversal g, WalkType c) => [g c s e] -> Walk c s e
+gUnion ts = unsafeWalk "union" $ map (toGremlin . toGTraversal) ts
+
+-- | @.choose@ step with if-then-else style.
+--
+-- >>> let key_age = ("age" :: Key AVertex Int)
+-- >>> toGremlin (source "g" & sV' [] &. gChoose3 (gHas2' key_age 30) (gIn' []) (gOut' []))
+-- "g.V().choose(__.has(\"age\",30),__.in(),__.out())"
+--
+-- @since 1.0.1.0
+gChoose3 :: (ToGTraversal g, Split cc c, WalkType cc, WalkType c)
+         => g cc s ep -- ^ the predicate traversal.
+         -> g c s e -- ^ The traversal executed if the predicate traversal outputs something.
+         -> g c s e -- ^ The traversal executed if the predicate traversal outputs nothing.
+         -> Walk c s e
+gChoose3 pt tt ft = unsafeWalk "choose"
+                    [ toGremlin $ toGTraversal pt,
+                      toGremlin $ toGTraversal tt,
+                      toGremlin $ toGTraversal ft
+                    ]
+
+-- | @.barrier@ step.
+--
+-- @since 1.0.1.0
+gBarrier :: WalkType c
+         => Maybe (Greskell Int)
+         -- ^ Max number of traversers kept at this barrier.
+         -> Walk c s s
+gBarrier mmax = unsafeWalk "barrier" $ maybe [] (\m -> [toGremlin m]) mmax
+
+-- | @.dedup@ step without argument.
+--
+-- @.dedup@ step is 'Transform' because the filtering decision depends
+-- on the sequence (order) of input elements.
+--
+-- >>> toGremlin (source "g" & sV' [] &. gDedup Nothing)
+-- "g.V().dedup()"
+-- >>> let key_age = ("age" :: Key AVertex Int)
+-- >>> toGremlin (source "g" & sV' [] &. gDedup (Just $ gBy key_age))
+-- "g.V().dedup().by(\"age\")"
+--
+-- @since 1.0.1.0
+gDedup :: Maybe (ByProjection s e)
+       -- ^ @.by@ modulator. If specified, the result of type @e@ is
+       -- used as the criterion of deduplication.
+       -> Walk Transform s s
+gDedup mp = gDedupGeneric [] mp
+
+-- | @.dedup@ step with at least one argument. The tuple specified by
+-- the 'AsLabel's is used as the criterion of deduplication.
+--
+-- >>> let label_a = ("a" :: AsLabel AVertex)
+-- >>> let label_b = ("b" :: AsLabel AVertex)
+-- >>> toGremlin (source "g" & sV' [] &. gAs label_a &. gOut' [] &. gAs label_b &. gDedupN label_a [label_b] Nothing)
+-- "g.V().as(\"a\").out().as(\"b\").dedup(\"a\",\"b\")"
+--
+-- @since 1.0.1.0
+gDedupN :: AsLabel a -> [AsLabel a] -> Maybe (ByProjection a e) -> Walk Transform s s
+gDedupN l ls mp = gDedupGeneric (map toGremlin (l : ls)) mp
+
+gDedupGeneric :: [Text] -> Maybe (ByProjection a b) -> Walk Transform s s
+gDedupGeneric args mp = 
+  case mp of
+    Nothing -> main_walk
+    Just (ByProjection g) -> modulateWith main_walk [unsafeWalk "by" [toGremlin g]]
+  where
+    main_walk = unsafeWalk "dedup" args
+
+
 -- | Data types that mean a projection from one type to another.
 class ProjectionLike p where
   type ProjectionLikeStart p
@@ -913,6 +1284,30 @@
 -- @since 0.2.0.0
 gV' :: [Greskell (ElementID AVertex)] -> Walk Transform s AVertex
 gV' = gV
+
+-- | @.constant@ step.
+--
+-- >>> toGremlin (source "g" & sV' [] &. gConstant (10 :: Greskell Int))
+-- "g.V().constant(10)"
+--
+-- @since 1.0.1.0
+gConstant :: Greskell a -> Walk Transform s a
+gConstant v = unsafeWalk "constant" [toGremlin v]
+
+-- | @.unfold@ step.
+--
+-- Note that we use 'AsIterator' here because basically the @.unfold@
+-- step does the same thing as @IteratorUtils.asIterator@ function in
+-- Tinkerpop. However, Tinkerpop's implementation of @.unfold@ step
+-- doesn't necessarily use @asIterator@, so there may be some corner
+-- cases where @asIterator@ and @.unfold@ step behave differently.
+--
+-- >>> toGremlin (source "g" & sV' [] &. gFold &. gUnfold)
+-- "g.V().fold().unfold()"
+--
+-- @since 1.0.1.0
+gUnfold :: AsIterator a => Walk Transform a (IteratorItem a)
+gUnfold = unsafeWalk "unfold" []
 
 -- | @.as@ step.
 --
diff --git a/test/Data/Greskell/GTraversalSpec.hs b/test/Data/Greskell/GTraversalSpec.hs
--- a/test/Data/Greskell/GTraversalSpec.hs
+++ b/test/Data/Greskell/GTraversalSpec.hs
@@ -22,13 +22,16 @@
 import Data.Greskell.Greskell
   ( toGremlin, Greskell, gvalueInt)
 import Data.Greskell.GTraversal
-  ( Walk, Transform,
+  ( Walk, Transform, Filter,
     source, (&.), ($.), sV', sE',
-    gHas1, gHas2, gHas2P, gHasLabelP, gHasIdP,
+    gHas1, gHas2, gHas2P, gHasLabelP, gHasIdP, gIs,
     gOut', gRange, gValues, gNot, gIn',
     gOrder,
     gProperties, gHasKeyP, gHasValueP,
-    ByComparator(..), gBy2, gBy1, gBy
+    ByComparator(..), gBy2, gBy1, gBy,
+    gRepeat, gTimes, gUntilHead, gUntilTail,
+    gEmitHead, gEmitTail, gEmitHeadT, gEmitTailT,
+    gLoops
   )
 
 
@@ -41,6 +44,7 @@
   spec_order_by
   spec_compose_steps
   spec_has
+  spec_repeat
 
 
 spec_GraphTraversalSource :: Spec
@@ -130,3 +134,33 @@
     specify "P" $ do
       toGremlin (source "g" & sV' [] &. gProperties ["age" :: Key e Int] &. gHasValueP (pGte 20))
         `shouldBe` "g.V().properties(\"age\").hasValue(P.gte(20))"
+
+spec_repeat :: Spec
+spec_repeat = do
+  let hasName :: Greskell Text -> Walk Filter AVertex AVertex
+      hasName v  = gHas2 keyName v
+      keyName :: Key AVertex Text
+      keyName = "name"
+  describe "gRepeat" $ do
+    specify "no modulation" $ do
+      toGremlin (source "g" & sV' [] &. gRepeat Nothing Nothing Nothing (gOut' []))
+        `shouldBe` "g.V().repeat(__.out())"
+    specify "gTimes and gEmitHead" $ do
+      toGremlin (source "g" & sV' [] &. gRepeat Nothing (gTimes 3) gEmitHead (gOut' []))
+        `shouldBe` "g.V().times(3).emit().repeat(__.out())"
+    specify "gUntilHead and gEmitTail" $ do
+      toGremlin (source "g" & sV' [] &. gRepeat Nothing (gUntilHead $ hasName "foo") gEmitTail (gOut' []))
+        `shouldBe` "g.V().until(__.has(\"name\",\"foo\")).repeat(__.out()).emit()"
+    specify "gUntilTail and gEmitHeadT" $ do
+      toGremlin (source "g" & sV' [] &. gRepeat Nothing (gUntilTail $ hasName "foo") (gEmitHeadT $ hasName "bar") (gOut' []))
+        `shouldBe` "g.V().emit(__.has(\"name\",\"bar\")).repeat(__.out()).until(__.has(\"name\",\"foo\"))"
+    specify "gUntilTail and gEmitTailT" $ do
+      toGremlin (source "g" & sV' [] &. gRepeat Nothing (gUntilTail $ hasName "foo") (gEmitTailT $ hasName "bar") (gOut' []))
+        `shouldBe` "g.V().repeat(__.out()).until(__.has(\"name\",\"foo\")).emit(__.has(\"name\",\"bar\"))"
+    specify "gLoops without label" $ do
+      toGremlin (source "g" & sV' [] &. gRepeat Nothing (gUntilTail $ gLoops Nothing >>> gIs 5) Nothing (gOut' []))
+        `shouldBe` "g.V().repeat(__.out()).until(__.loops().is(5))"
+    specify "gLoops with label" $ do
+      let loop_label = "LP"
+      toGremlin (source "g" & sV' [] &. gRepeat (Just loop_label) (gUntilTail $ gLoops (Just loop_label) >>> gIs 5) Nothing (gOut' []))
+        `shouldBe` "g.V().repeat(\"LP\",__.out()).until(__.loops(\"LP\").is(5))"
diff --git a/test/ServerTest.hs b/test/ServerTest.hs
--- a/test/ServerTest.hs
+++ b/test/ServerTest.hs
@@ -50,7 +50,8 @@
     gAs, gSelect1, gSelectN, gSelectBy1, gSelectByN,
     gFilter, gOut', gOutV, gOutV', gInV, gInV', gId, gLabel, gProject,
     gValueMap,
-    gProject, gByL
+    gProject, gByL,
+    gRepeat, gTimes, gEmitHead, gUntilTail, gLoops, gIsP
   )
 import Data.Greskell.PMap (lookupAsM, lookupListAs, pMapToThrow)
 
@@ -70,6 +71,7 @@
   spec_as
   spec_selectBy
   spec_project
+  spec_repeat
 
 spec_basics :: SpecWith (String,Int)
 spec_basics = do
@@ -454,3 +456,24 @@
     got <- fmap V.toList $ WS.slurpResults =<< WS.submit client trav Nothing
     traverse (lookupAsM l_mapped) got `shouldReturn` [4, 8, 12]
     traverse (lookupAsM l_orig) got `shouldReturn` [1, 2, 3]
+
+spec_repeat :: SpecWith (String,Int)
+spec_repeat = do
+  specify "gRepeat and gTimes" $ withClient $ \client -> do
+    let start :: GTraversal Transform () Int
+        start = unsafeGTraversal "__(1,2,3)"
+        trav = gRepeat Nothing (gTimes 3) Nothing (multiplyWalk 2) $. start
+    got <- fmap V.toList $ WS.slurpResults =<< WS.submit client trav Nothing
+    got `shouldBe` [8, 16, 24]
+  specify "gRepeat, gTimes and gEmitHead" $ withClient $ \client -> do
+    let start :: GTraversal Transform () Int
+        start = unsafeGTraversal "__(1, 10, 100)"
+        trav = gRepeat Nothing (gTimes 3) gEmitHead (multiplyWalk 2) $. start
+    got <- fmap V.toList $ WS.slurpResults =<< WS.submit client trav Nothing
+    sort got `shouldBe` [1, 2, 4, 8, 10, 20, 40, 80, 100, 200, 400, 800]
+  specify "gRepeat, gUntilTail and gLoops" $ withClient $ \client -> do
+    let start :: GTraversal Transform () Int
+        start = unsafeGTraversal "__(1, 10, 100)"
+        trav = gRepeat Nothing (gUntilTail $ gIsP (pGte 4) <<< gLoops Nothing) Nothing (multiplyWalk 2) $. start
+    got <- fmap V.toList $ WS.slurpResults =<< WS.submit client trav Nothing
+    sort got `shouldBe` [16, 160, 1600]
