diff --git a/program/tests/test_playlists.py b/program/tests/test_playlists.py
new file mode 100644
index 0000000000000000000000000000000000000000..0a79998716ce7c0584cba4388a53c91c4a5719c3
--- /dev/null
+++ b/program/tests/test_playlists.py
@@ -0,0 +1,114 @@
+import random
+
+import pytest
+
+from conftest import assert_data
+from program.tests.factories import PlaylistFactory
+
+pytestmark = pytest.mark.django_db
+
+
+def url(playlist=None):
+    if playlist:
+        return f"/api/v1/playlists/{playlist.id}/"
+    else:
+        return "/api/v1/playlists/"
+
+
+def playlist_data(owned_show):
+    return {
+        "description": "DESCRIPTION",
+        "show_id": owned_show.id,
+    }
+
+
+def playlist_entries_data(show, file_id, entries=1):
+    return [
+        {
+            "duration": random.uniform(1975, 2024),
+            "file_id": file_id,
+            "line_num": n,
+            "uri": f"file://{show.id}/{file_id}",
+        }
+        for n in range(entries)
+    ]
+
+
+def test_create_playlist(
+    user_with_playlist_perms, api_client_playlist_perms, owned_show_playlist_perms
+):
+    data = playlist_data(owned_show_playlist_perms)
+
+    response = api_client_playlist_perms.post(url(), data=data)
+
+    assert response.status_code == 201
+
+    assert_data(response, data)
+
+
+def test_retrieve_playlist(user_with_playlist_perms, api_client_playlist_perms, show, playlist):
+    response = api_client_playlist_perms.get(url(playlist=playlist))
+
+    assert response.status_code == 200
+
+
+def test_list_playlists(api_client_playlist_perms, show):
+    PLAYLISTS = 3
+    PlaylistFactory.create_batch(size=PLAYLISTS, show=show)
+
+    response = api_client_playlist_perms.get(url())
+
+    assert response.status_code == 200
+    assert len(response.data) == PLAYLISTS
+
+
+def test_delete_playlist(api_client_playlist_perms, owned_show_playlist_perms, playlist):
+    response = api_client_playlist_perms.delete(url(playlist=playlist))
+
+    print(response.data)
+
+    assert response.status_code == 204
+
+
+def test_update_description(api_client_playlist_perms, owned_show_playlist_perms, playlist):
+    update = {"description": "DESCRIPTION"}
+
+    response = api_client_playlist_perms.patch(url(playlist=playlist), data=update)
+
+    assert response.status_code == 200
+    assert response.data["description"] == update["description"]
+
+
+def test_update_playout_mode(api_client_playlist_perms, owned_show_playlist_perms, playlist):
+    update = {"playout_mode": "LINEAR"}
+
+    response = api_client_playlist_perms.patch(url(playlist=playlist), data=update, format="json")
+    print(response.data)
+    assert response.status_code == 200
+    assert response.data["playout_mode"] == update["playout_mode"]
+
+
+def test_update_entries(api_client_playlist_perms, owned_show_playlist_perms, playlist):
+    playlist_entries = playlist_entries_data(owned_show_playlist_perms, 42, 3)
+
+    update = {"entries": playlist_entries}
+
+    response = api_client_playlist_perms.patch(url(playlist=playlist), data=update, format="json")
+
+    assert response.status_code == 200
+
+    for entry, update in zip(response.data["entries"], update["entries"]):
+        assert entry["duration"] == update["duration"]
+        assert entry["file_id"] == update["file_id"]
+        assert entry["uri"] == update["uri"]
+
+
+def test_clear_entries(
+    api_client_playlist_perms, owned_show_playlist_perms, playlist, playlist_entry
+):
+    update = {"entries": []}
+
+    response = api_client_playlist_perms.patch(url(playlist=playlist), data=update, format="json")
+
+    assert response.status_code == 200
+    assert len(response.data["entries"]) == 0