Repository: nicklaw5/helix
Pull request #144 (2022-10-05 23:32:08)

feat: add get chat chatters
- add get chat chatters api
- add unit test for get chatters

coveralls: ## Pull Request Test Coverage Report for [Build 3193411741](https://coveralls.io/builds/53045801)

* **12** of **14**   **(85.71%)**  changed or added relevant lines in **1** file are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage decreased (**-0.07%**) to **92.547%**

---

|  Changes Missing Coverage | Covered Lines | Changed/Added Lines | % |
| :-----|--------------|--------|---: |
| [chat.go](https://coveralls.io/builds/53045801/source?filename=chat.go#L34) | 12 | 14 | 85.71%
<!-- | **Total:** | **12** | **14** | **85.71%** | -->


|  Totals | [![Coverage Status](https://coveralls.io/builds/53045801/badge)](https://coveralls.io/builds/53045801) |
| :-- | --: |
| Change from base [Build 3076286834](https://coveralls.io/builds/52556588): |  -0.07% |
| Covered Lines: | 1279 |
| Relevant Lines: | 1382 |

---
##### 💛  - [Coveralls](https://coveralls.io)


Patch:
diff --git a/chat.go b/chat.go
index f790a7d..2db3ea1 100644
--- a/chat.go
+++ b/chat.go
@@ -1,5 +1,45 @@
 package helix
 
+import "errors"
+
+type GetChatChattersParams struct {
+	BroadcasterID string `query:"broadcaster_id"`
+	ModeratorID   string `query:"broadcaster_id"`
+	After         string `query:"after"`
+	First         string `query:"first"`
+}
+
+type ChatChatter struct {
+	UserLogin string `json:"user_login"`
+}
+
+type ManyChatChatters struct {
+	Chatters   []ChatChatter `json:"data"`
+	Pagination Pagination  `json:"pagination"`
+}
+
+type GetChatChattersResponse struct {
+	ResponseCommon
+	Data ManyChatChatters
+}
+
+// Required scope: moderator:read:chatters
+func (c *Client) GetChannelChatChatters(params *GetChatChattersParams) (*GetChatChattersResponse, error) {
+	if params.BroadcasterID == "" || params.ModeratorID == "" {
+		return nil, errors.New("error: broadcaster and moderator identifiers must be provided")
+	}
+	resp, err := c.get("/chat/chatters", &ManyChatChatters{}, params)
+	if err != nil {
+		return nil, err
+	}
+
+	chatters := &GetChatChattersResponse{}
+	resp.HydrateResponseCommon(&chatters.ResponseCommon)
+	chatters.Data.Chatters = resp.Data.(*ManyChatChatters).Chatters
+
+	return chatters, nil
+}
+
 type GetChatBadgeParams struct {
 	BroadcasterID string `query:"broadcaster_id"`
 }


Test patch:
diff --git a/chat_test.go b/chat_test.go
index 04ea5d2..6f56e01 100644
--- a/chat_test.go
+++ b/chat_test.go
@@ -5,6 +5,72 @@ import (
 	"testing"
 )
 
+func TestGetChannelChatChatterss(t *testing.T) {
+	t.Parallel()
+
+	testCases := []struct {
+		statusCode            int
+		options               *Options
+		GetChatChattersParams *GetChatChattersParams
+		respBody              string
+		validationErr         string
+	}{
+		{
+			http.StatusBadRequest,
+			&Options{ClientID: "my-client-id"},
+			&GetChatChattersParams{BroadcasterID: "", ModeratorID: "1234"},
+			``,
+			"error: broadcaster and moderator identifiers must be provided",
+		},
+		{
+			http.StatusOK,
+			&Options{ClientID: "my-client-id"},
+			&GetChatChattersParams{BroadcasterID: "121445595", ModeratorID: "1234"},
+			`{"data": [{"user_login": "smittysmithers"}]}`,
+			"",
+		},
+		{
+			http.StatusBadRequest,
+			&Options{ClientID: "my-client-id"},
+			&GetChatChattersParams{BroadcasterID: "1231", ModeratorID: "1234"},
+			`{"error":"Bad Request","status":400,"message":"Missing required parameter \"broadcaster_id\""}`,
+			"",
+		},
+	}
+
+	for _, testCase := range testCases {
+		c := newMockClient(testCase.options, newMockHandler(testCase.statusCode, testCase.respBody, nil))
+
+		resp, err := c.GetChannelChatChatters(testCase.GetChatChattersParams)
+		if err != nil {
+			if err.Error() == testCase.validationErr {
+				continue
+			}
+			t.Error(err)
+		}
+
+		if resp.StatusCode != testCase.statusCode {
+			t.Errorf("expected status code to be %d, got %d", testCase.statusCode, resp.StatusCode)
+		}
+
+		if resp.StatusCode == http.StatusBadRequest {
+			if resp.Error != "Bad Request" {
+				t.Errorf("expected error to be %s, got %s", "Bad Request", resp.Error)
+			}
+
+			if resp.ErrorStatus != http.StatusBadRequest {
+				t.Errorf("expected error status to be %d, got %d", http.StatusBadRequest, resp.ErrorStatus)
+			}
+
+			continue
+		}
+
+		if len(resp.Data.Chatters) != 1 {
+			t.Errorf("expected %d chatters got %d", 1, len(resp.Data.Chatters))
+		}
+	}
+}
+
 func TestGetChannelChatBadges(t *testing.T) {
 	t.Parallel()
 
diff --git a/extensions_test.go b/extensions_test.go
index 2e963e4..6f5ad23 100644
--- a/extensions_test.go
+++ b/extensions_test.go
@@ -114,7 +114,7 @@ func TestGetExtensionLiveChannels(t *testing.T) {
 			http.StatusOK,
 			&Options{ClientID: "my-client-id"},
 			&ExtensionLiveChannelsParams{ExtensionID: "some-extension-id"},
-			`{ "data": [{ "broadcaster_id": "121086094", "broadcaster_name": "khaizer93", "game_name": "Art", "game_id": "509660", "title": "random artstream sketching Kiryu COCO" }, { "broadcaster_id": "165951395", "broadcaster_name": "MelloTodd", "game_name": "Jackbox Party Packs", "game_id": "493174", "title": "[OPEN] WInner Choses Next Game (1-8) | !jackbox !uptime #envtuber" }, { "broadcaster_id": "21724294", "broadcaster_name": "Mahoog47", "game_name": "Escape from Tarkov", "game_id": "491931", "title": "LVL 39| The holy relic Ash-12 has been acquired" }, { "broadcaster_id": "253663808", "broadcaster_name": "MrHatcher_", "game_name": "Dota 2", "game_id": "29595", "title": "Road to 53/55 followers! Dota 2 Ranked 1k mmr (british/filipino)" }, { "broadcaster_id": "245641098", "broadcaster_name": "ChoKoii", "game_name": "Escape from Tarkov", "game_id": "491931", "title": "First Drops Enabled Stream? | Labs Main | 1 Follower=5 push-ups" }, { "broadcaster_id": "268444856", "broadcaster_name": "D4RK_5KY", "game_name": "Always On", "game_id": "499973", "title": "24/7 FULLSEND HOST RAFFLE - Need THAT #SUPPORT!? #Affiliate PUSH!? Try Your LUCK \u0026 WIN The Raffle!" }, { "broadcaster_id": "42871388", "broadcaster_name": "mieudiary", "game_name": "Stardew Valley", "game_id": "490744", "title": "I'm very sleepy but let's farm | !melaomi" }, { "broadcaster_id": "429972112", "broadcaster_name": "andy_gra", "game_name": "twitch", "game_id": "", "title": "wbijaj smialo :)" }, { "broadcaster_id": "486154226", "broadcaster_name": "mrboone521", "game_name": "Escape from Tarkov", "game_id": "491931", "title": "TARK TARK offline and scav runs" }, { "broadcaster_id": "503028811", "broadcaster_name": "Uwlsy2k", "game_name": "Fortnite", "game_id": "33214", "title": "Bot Zonewars?! Join up and chat " }, { "broadcaster_id": "520878515", "broadcaster_name": "me_fon", "game_name": "Teamfight Tactics", "game_id": "513143", "title": "Ranking up in TFT Mob" }, { "broadcaster_id": "521301629", "broadcaster_name": "acrolic_", "game_name": "Apex Legends", "game_id": "511224", "title": "Come say hi! |road to 50 followers | song choices" }, { "broadcaster_id": "54270050", "broadcaster_name": "ELIASS_1", "game_name": "SCUM", "game_id": "495811", "title": "walking simulator 2022 | !setup | !sleep  | 386/400 followers | " }, { "broadcaster_id": "611701485", "broadcaster_name": "Semmy_22", "game_name": "Overwatch", "game_id": "488552", "title": "Support slave at your service " }, { "broadcaster_id": "63501619", "broadcaster_name": "KittySinisterr", "game_name": "Fortnite", "game_id": "33214", "title": "Winterfest challenges" }, { "broadcaster_id": "625059457", "broadcaster_name": "unisclan", "game_name": "Battlefield 2042", "game_id": "514974", "title": "crazy gameplay tanks   will not live " }, { "broadcaster_id": "604281079", "broadcaster_name": "viperarishyt", "game_name": "FIFA 22", "game_id": "1869092879", "title": "Grab Your Breakfast and Join me. Lets chat :-)" }, { "broadcaster_id": "666411722", "broadcaster_name": "SarahBree", "game_name": "Apex Legends", "game_id": "511224", "title": "Winter express only before it goes away :'(" }, { "broadcaster_id": "647613771", "broadcaster_name": "batbat0508", "game_name": "Battlefield 4", "game_id": "66402", "title": "( GOVS ) ~Fr-En ~ rules (LOCKER)" }, { "broadcaster_id": "653487605", "broadcaster_name": "honka2019", "game_name": "Identity V", "game_id": "508662", "title": "JPN♡本日も23:30頃までまったりプレイ⚠️mobile play" }], "pagination": "YVc1emRHRnNiQ00yTXpVd01UWXhPVHBsT1ROalpqZzNNekJ1WkRFeGVqZG5aWEJyYkhreVozSjVOV3QyT0dzNjoz" }`,		"",
+			`{ "data": [{ "broadcaster_id": "121086094", "broadcaster_name": "khaizer93", "game_name": "Art", "game_id": "509660", "title": "random artstream sketching Kiryu COCO" }, { "broadcaster_id": "165951395", "broadcaster_name": "MelloTodd", "game_name": "Jackbox Party Packs", "game_id": "493174", "title": "[OPEN] WInner Choses Next Game (1-8) | !jackbox !uptime #envtuber" }, { "broadcaster_id": "21724294", "broadcaster_name": "Mahoog47", "game_name": "Escape from Tarkov", "game_id": "491931", "title": "LVL 39| The holy relic Ash-12 has been acquired" }, { "broadcaster_id": "253663808", "broadcaster_name": "MrHatcher_", "game_name": "Dota 2", "game_id": "29595", "title": "Road to 53/55 followers! Dota 2 Ranked 1k mmr (british/filipino)" }, { "broadcaster_id": "245641098", "broadcaster_name": "ChoKoii", "game_name": "Escape from Tarkov", "game_id": "491931", "title": "First Drops Enabled Stream? | Labs Main | 1 Follower=5 push-ups" }, { "broadcaster_id": "268444856", "broadcaster_name": "D4RK_5KY", "game_name": "Always On", "game_id": "499973", "title": "24/7 FULLSEND HOST RAFFLE - Need THAT #SUPPORT!? #Affiliate PUSH!? Try Your LUCK \u0026 WIN The Raffle!" }, { "broadcaster_id": "42871388", "broadcaster_name": "mieudiary", "game_name": "Stardew Valley", "game_id": "490744", "title": "I'm very sleepy but let's farm | !melaomi" }, { "broadcaster_id": "429972112", "broadcaster_name": "andy_gra", "game_name": "twitch", "game_id": "", "title": "wbijaj smialo :)" }, { "broadcaster_id": "486154226", "broadcaster_name": "mrboone521", "game_name": "Escape from Tarkov", "game_id": "491931", "title": "TARK TARK offline and scav runs" }, { "broadcaster_id": "503028811", "broadcaster_name": "Uwlsy2k", "game_name": "Fortnite", "game_id": "33214", "title": "Bot Zonewars?! Join up and chat " }, { "broadcaster_id": "520878515", "broadcaster_name": "me_fon", "game_name": "Teamfight Tactics", "game_id": "513143", "title": "Ranking up in TFT Mob" }, { "broadcaster_id": "521301629", "broadcaster_name": "acrolic_", "game_name": "Apex Legends", "game_id": "511224", "title": "Come say hi! |road to 50 followers | song choices" }, { "broadcaster_id": "54270050", "broadcaster_name": "ELIASS_1", "game_name": "SCUM", "game_id": "495811", "title": "walking simulator 2022 | !setup | !sleep  | 386/400 followers | " }, { "broadcaster_id": "611701485", "broadcaster_name": "Semmy_22", "game_name": "Overwatch", "game_id": "488552", "title": "Support slave at your service " }, { "broadcaster_id": "63501619", "broadcaster_name": "KittySinisterr", "game_name": "Fortnite", "game_id": "33214", "title": "Winterfest challenges" }, { "broadcaster_id": "625059457", "broadcaster_name": "unisclan", "game_name": "Battlefield 2042", "game_id": "514974", "title": "crazy gameplay tanks   will not live " }, { "broadcaster_id": "604281079", "broadcaster_name": "viperarishyt", "game_name": "FIFA 22", "game_id": "1869092879", "title": "Grab Your Breakfast and Join me. Lets chat :-)" }, { "broadcaster_id": "666411722", "broadcaster_name": "SarahBree", "game_name": "Apex Legends", "game_id": "511224", "title": "Winter express only before it goes away :'(" }, { "broadcaster_id": "647613771", "broadcaster_name": "batbat0508", "game_name": "Battlefield 4", "game_id": "66402", "title": "( GOVS ) ~Fr-En ~ rules (LOCKER)" }, { "broadcaster_id": "653487605", "broadcaster_name": "honka2019", "game_name": "Identity V", "game_id": "508662", "title": "JPN♡本日も23:30頃までまったりプレイ⚠️mobile play" }], "pagination": "YVc1emRHRnNiQ00yTXpVd01UWXhPVHBsT1ROalpqZzNNekJ1WkRFeGVqZG5aWEJyYkhreVozSjVOV3QyT0dzNjoz" }`, "",
 		},
 		{
 			http.StatusOK,