diff --git a/mypy.ini b/mypy.ini
--- a/mypy.ini
+++ b/mypy.ini
@@ -2,7 +2,6 @@
 namespace_packages = True
 warn_unused_ignores = True
 
-
 # 3rd party libraries without stubs (yet)
 
 [mypy-pkg_resources.*]
@@ -11,5 +10,11 @@
 [mypy-pytest.*]
 ignore_missing_imports = True
 
+[mypy-uvicorn.*]
+ignore_missing_imports = True
+
+[mypy-requests.*]
+ignore_missing_imports = True
+
 # [mypy-add_your_lib_here.*]
 # ignore_missing_imports = True
diff --git a/swh/graphql/server.py b/swh/graphql/server.py
--- a/swh/graphql/server.py
+++ b/swh/graphql/server.py
@@ -1,3 +1,8 @@
+# Copyright (C) 2022 The Software Heritage developers
+# See the AUTHORS file at the top-level directory of this distribution
+# License: GNU General Public License version 3, or any later version
+# See top-level LICENSE file for more information
+
 import os
 from typing import Any, Dict, Optional
 
@@ -42,7 +47,7 @@
     return cfg
 
 
-def make_app_from_configfile():
+def make_app_from_configfile(config_path=""):
     """Loading the configuration from
     a configuration file.
 
@@ -55,7 +60,7 @@
     global graphql_cfg
 
     if not graphql_cfg:
-        config_path = os.environ.get("SWH_CONFIG_FILENAME")
+        config_path = os.environ.get("SWH_CONFIG_FILENAME") or config_path
         graphql_cfg = load_and_check_config(config_path)
 
     if graphql_cfg.get("server-type") == "asgi":
diff --git a/swh/graphql/tests/conftest.py b/swh/graphql/tests/conftest.py
new file mode 100644
--- /dev/null
+++ b/swh/graphql/tests/conftest.py
@@ -0,0 +1,49 @@
+# Copyright (C) 2022 The Software Heritage developers
+# See the AUTHORS file at the top-level directory of this distribution
+# License: GNU General Public License version 3, or any later version
+# See top-level LICENSE file for more information
+
+from multiprocessing import Process
+import time
+
+from _pytest.monkeypatch import MonkeyPatch
+import pytest
+import uvicorn
+
+from swh.graphql import server as app_server
+from swh.storage import get_storage as get_swhstorage
+
+from .data import populate_dummy_data
+
+
+@pytest.fixture(scope="session")
+def sessionmonkeypatch(*args, **kw):
+    sessionpatch = MonkeyPatch()
+    yield sessionpatch
+    sessionpatch.undo()
+
+
+@pytest.fixture(scope="session")
+def storage(sessionmonkeypatch):
+    def mock_storage(*args, **kw):
+        storage = get_swhstorage(cls="memory")
+        populate_dummy_data(storage)
+        return storage
+
+    sessionmonkeypatch.setattr(app_server, "get_storage", mock_storage)
+
+
+def run_server():
+    app = app_server.make_app_from_configfile("config/dev.yml")
+    # Using a different port
+    uvicorn.run(app, host="localhost", port=9834, log_level="info")
+
+
+@pytest.fixture(scope="session")
+def server(storage):
+    proc = Process(target=run_server, args=(), daemon=True)
+    proc.start()
+    # Wait for the server to start; in session scope
+    time.sleep(5)
+    yield
+    proc.kill()
diff --git a/swh/graphql/tests/data.py b/swh/graphql/tests/data.py
new file mode 100644
--- /dev/null
+++ b/swh/graphql/tests/data.py
@@ -0,0 +1,105 @@
+# Copyright (C) 2022 The Software Heritage developers
+# See the AUTHORS file at the top-level directory of this distribution
+# License: GNU General Public License version 3, or any later version
+# See top-level LICENSE file for more information
+
+# This module will be removed once the test data
+# generation in SWH-wb moved to a shared location
+# or to a new test data project
+
+from datetime import timedelta
+
+from swh.model.model import Origin, OriginVisit, OriginVisitStatus, Snapshot
+from swh.storage.utils import now
+
+
+def populate_dummy_data(storage):
+    origins = get_origins()
+    visits = get_visits(origins)
+    snapshots = get_snapshots()
+    status = get_visit_status(visits, snapshots)
+
+    storage.origin_add(origins)
+    storage.origin_visit_add(visits)
+    storage.snapshot_add(snapshots)
+    storage.origin_visit_status_add(status)
+
+
+def get_origins():
+    # Return two dummy origins
+    return [
+        Origin(url="http://example.com/forge1"),
+        Origin(url="http://example.com/forge2"),
+    ]
+
+
+def get_visits(origins):
+    # Return two visits each for an origin
+    origin1, origin2 = origins
+    return [
+        OriginVisit(
+            origin=origin1.url,
+            date=now() - timedelta(minutes=200),
+            type="git",
+            visit=1,
+        ),
+        OriginVisit(
+            origin=origin1.url,
+            date=now(),
+            type="git",
+            visit=2,
+        ),
+        OriginVisit(
+            origin=origin2.url,
+            date=now() - timedelta(minutes=500),
+            type="hg",
+            visit=1,
+        ),
+        OriginVisit(
+            origin=origin2.url,
+            date=now(),
+            type="hg",
+            visit=2,
+        ),
+    ]
+
+
+def get_visit_status(visits, snapshots):
+    # Return one status per visit, adding only empty statpshots for now
+    visit1, visit2, visit3, visit4 = visits
+    (empty_snapshot,) = snapshots
+    return [
+        OriginVisitStatus(
+            origin=visit1.origin,
+            visit=visit1.visit,
+            date=visit1.date,
+            status="full",
+            snapshot=empty_snapshot.id,
+        ),
+        OriginVisitStatus(
+            origin=visit2.origin,
+            visit=visit2.visit,
+            date=visit1.date,
+            status="full",
+            snapshot=empty_snapshot.id,
+        ),
+        OriginVisitStatus(
+            origin=visit3.origin,
+            visit=visit3.visit,
+            date=visit3.date,
+            status="full",
+            snapshot=empty_snapshot.id,
+        ),
+        OriginVisitStatus(
+            origin=visit4.origin,
+            visit=visit4.visit,
+            date=visit4.date,
+            status="full",
+            snapshot=empty_snapshot.id,
+        ),
+    ]
+
+
+def get_snapshots():
+    empty_snapshot = Snapshot(branches={})
+    return [empty_snapshot]
diff --git a/swh/graphql/tests/functional/test_origin.py b/swh/graphql/tests/functional/test_origin.py
new file mode 100644
--- /dev/null
+++ b/swh/graphql/tests/functional/test_origin.py
@@ -0,0 +1,84 @@
+# Copyright (C) 2022 The Software Heritage developers
+# See the AUTHORS file at the top-level directory of this distribution
+# License: GNU General Public License version 3, or any later version
+# See top-level LICENSE file for more information
+
+from .test_utils import get_query_response
+
+
+class TestOriginConnection:
+    def test_get(self, server):
+        query_str = """
+        {
+          origins(first: 10) {
+            nodes {
+              url
+            }
+          }
+        }
+        """
+        data, _ = get_query_response(query_str)
+        assert len(data["origins"]["nodes"]) == 2
+
+    def test_basic_pagination(self, server):
+        query_str = """
+        {
+          origins(first: 2) {
+            nodes {
+              id
+            }
+            pageInfo {
+              hasNextPage
+              endCursor
+            }
+          }
+        }
+        """
+
+        data, _ = get_query_response(query_str)
+        assert len(data["origins"]["nodes"]) == 2
+        assert data["origins"]["pageInfo"] == {"hasNextPage": False, "endCursor": None}
+
+
+class TestOriginNode:
+    def test_invalid_get(self, server):
+        query_str = """
+        {
+          origin(url: "http://example.com/forge1/") {
+            url
+          }
+        }
+        """
+        data, errors = get_query_response(query_str)
+        assert data["origin"] is None
+        assert len(errors) == 1
+        assert errors[0]["message"] == "Requested object is not available"
+
+    def test_get(self, server):
+        query_str = """
+        {
+          origin(url: "http://example.com/forge1") {
+            url
+            id
+            visits(first: 10) {
+              nodes {
+                id
+              }
+            }
+            latestVisit {
+              visitId
+            }
+            snapshots(first: 2) {
+              nodes {
+                id
+              }
+            }
+          }
+        }
+        """
+        data, _ = get_query_response(query_str)
+        origin = data["origin"]
+        assert origin["url"] == "http://example.com/forge1"
+        assert len(origin["visits"]["nodes"]) == 2
+        assert origin["latestVisit"]["visitId"] == 2
+        assert len(origin["snapshots"]["nodes"]) == 1
diff --git a/swh/graphql/tests/functional/test_utils.py b/swh/graphql/tests/functional/test_utils.py
new file mode 100644
--- /dev/null
+++ b/swh/graphql/tests/functional/test_utils.py
@@ -0,0 +1,15 @@
+# Copyright (C) 2022 The Software Heritage developers
+# See the AUTHORS file at the top-level directory of this distribution
+# License: GNU General Public License version 3, or any later version
+# See top-level LICENSE file for more information
+
+import requests
+
+
+def get_query_response(query_str):
+    url = "http://localhost:9834/"  # test server URL
+    response = requests.post(url, json={"query": query_str})
+    assert response.status_code == 200
+    result = response.json()
+    data, errors = result.get("data"), result.get("errors")
+    return data, errors