 EXISTING_ID = null
 
 #
+# Asserts that the given actual *text string* is a valid JSONP response,
+# wrapping a Response info object in a call to the given function name.
+#
+# May also optionally match the response with the given expected object
+# (which may be partial).
+#
+expectJSONP = (act, callback, exp={}) ->
+    # instead of testing the string via regex (which is brittle since e.g.
+    # Express adds a typeof check before calling the callback function),
+    # just do the "real" thing and evaluate the string as JS directly:
+    act = VM.runInNewContext """
+        function #{callback}(resp) {
+            return resp;
+        }
+
+        #{act}
+    """
+
+    expectResponse act, exp
+
+#
+# Asserts that the given actual object is a valid Response info object,
+# optionally matching the given expected object (which may be partial).
+#
+expectResponse = (act, exp={}) ->
+    expect(act).to.be.an 'object'
+
+    _expectNumberWithin act.status, 200, 599
+    _expectStringMatching act.statusText, /.+/
+
+    if act.redirectLocation
+        _expectFlexibleURL act.redirectLocation
+
+    # responses must contain one of `content`, `dzi`, or `error`:
+    if act.content
+        expectContent act.content, exp.content
+        delete exp.content  # so it's not deep-equaled below
+        expect(act).to.not.have.key 'dzi'
+        expect(act).to.not.have.key 'error'
+    if act.dzi
+        expect(act).to.not.have.key 'content'
+        expectDzi act.dzi, exp.dzi
+        delete exp.dzi  # so it's not deep-equaled below
+        expect(act).to.not.have.key 'error'
+    if act.error
+        expect(act).to.not.have.key 'content'
+        expect(act).to.not.have.key 'dzi'
+        _expectStringMatching act.error, /.+/
+
+    _expectPartial act, exp
+
+#
 # Asserts that the given actual object is a valid Content info object,
 # optionally matching the given expected object (which may be partial).
 #

# Asserts that the given actual object matches the given expected object,
# which may be partial. IOW, the actual object must be a superset.
#
_expectPartial = (act, exp={}) ->
    expect(act).to.be.an 'object'
    for prop of exp
        expect(act[prop]).to.eql exp[prop]

_expectStringMatching = (val, regex) ->
    expect(val).to.be.a 'string'
    expect(val).to.match regex

_expectURL = (val) ->
    _expectStringMatching val, /// ^https?://.+ ///


## Tests

    expect(act).to.be.an 'object'

    _expectStringMatching act.id, /\w+/
    _expectAbsoluteURL act.url

    for prop in ['ready', 'failed']
        expect(act[prop]).to.be.a 'boolean'

    _expectNumberWithin act.progress, 0, 1

    # TODO: Do we want to test the actual makeup of these properties?
    # E.g. that the share URL is to the website with the same ID, etc.
    _expectAbsoluteURL act.shareUrl
    _expectStringMatching act.embedHtml, /// ^<script .+></script>$ ///

    if act.ready or act.dzi
        expectDZI act.dzi, exp.dzi
        delete exp.dzi  # so it's not deep-equaled below

    _expectPartial act, exp

