Repository: twitch-apis/twitch-js (js)

Issue:
Bug: isSelf is false for membership commands
## Expected behavior

`isSelf === true` or `isSelf === undefined` for membership commands (cc @T1MOXA https://github.com/twitch-apis/twitch-js/issues/145#issuecomment-420771512).

## Actual behavior

`isSelf === false`

## Steps to reproduce

Issue a membership command and check the event's `isSelf` property.

## Your environment

* Operating system(s): n/a
* TwitchJS version: v2
* NodeJS version: n/a
* Browser(s): n/a

## Additional discussion

All memberships commands are _self_ commands, so is `isSelf` necessary for these events? Should it be set to `undefined` or should it be set to `true` to maintain consistency?

Pull request description:
Bugfix: force `isSelf` to `true` on certain events
## Proposed changes

Fixes #157 by adding a workaround on concerned events, until a better solution can be implemented.

## Types of changes

* [x] Bugfix (non-breaking change which fixes an issue)

## Checklist

* [x] I have read the [CONTRIBUTING](https://github.com/twitch-apis/twitch-js/blob/master/CONTRIBUTING.md) doc
* [x] My PR is named according to [CONTRIBUTING](https://github.com/twitch-apis/twitch-js/blob/master/CONTRIBUTING.md) doc
* [x] Lint and unit tests pass locally with my changes
* [x] I have added tests that prove my fix is effective or that my feature works
* [x] I have added necessary documentation (if appropriate)
* [x] Any dependent changes have been merged and published in downstream modules

Patch:
diff --git a/src/Chat/index.js b/src/Chat/index.js
index c44697b..5ba10f7 100644
--- a/src/Chat/index.js
+++ b/src/Chat/index.js
@@ -326,7 +326,7 @@ class Chat extends EventEmitter {
           new Errors.TimeoutError(constants.ERROR_JOIN_TIMED_OUT),
         ),
         join,
-      ])
+      ]),
     )
   }
 
@@ -357,7 +357,9 @@ class Chat extends EventEmitter {
 
     const say = Promise.all([this.connect, userState])
 
-    const send = this.send(`${constants.COMMANDS.PRIVATE_MESSAGE} ${channel} :${message}`)
+    const send = this.send(
+      `${constants.COMMANDS.PRIVATE_MESSAGE} ${channel} :${message}`,
+    )
 
     return send.then(() =>
       Promise.race([
@@ -366,7 +368,7 @@ class Chat extends EventEmitter {
           constants.ERROR_SAY_TIMED_OUT,
         ),
         say,
-      ])
+      ]),
     )
   }
 
@@ -451,43 +453,55 @@ function handleMessage(baseMessage) {
 
   const preMessage = { ...baseMessage, isSelf }
 
+  let eventName = preMessage.command
+  let message = preMessage
+
   switch (preMessage.command) {
     case constants.EVENTS.JOIN: {
-      const message = parsers.joinOrPartMessage(preMessage)
-      this.emit(`${message.command}/${channel}`, message)
+      message = parsers.joinOrPartMessage(preMessage)
+      message.isSelf = true
+      eventName = `${message.command}/${channel}`
       break
     }
+
     case constants.EVENTS.PART: {
-      const message = parsers.joinOrPartMessage(preMessage)
-      this.emit(`${message.command}/${channel}`, message)
+      message = parsers.joinOrPartMessage(preMessage)
+      message.isSelf = true
+      eventName = `${message.command}/${channel}`
       break
     }
+
     case constants.EVENTS.NAMES: {
-      const message = parsers.namesMessage(preMessage)
-      this.emit(`${message.command}/${channel}`, message)
+      message = parsers.namesMessage(preMessage)
+      message.isSelf = true
+      eventName = `${message.command}/${channel}`
       break
     }
+
     case constants.EVENTS.NAMES_END: {
-      const message = parsers.namesEndMessage(preMessage)
-      this.emit(`${message.command}/${channel}`, message)
+      message = parsers.namesEndMessage(preMessage)
+      message.isSelf = true
+      eventName = `${message.command}/${channel}`
       break
     }
+
     case constants.EVENTS.CLEAR_CHAT: {
-      const message = parsers.clearChatMessage(preMessage)
-      const eventName = message.event
+      message = parsers.clearChatMessage(preMessage)
+      eventName = message.event
         ? `${message.command}/${message.event}/${channel}`
         : `${message.command}/${channel}`
-
-      this.emit(eventName, message)
       break
     }
+
     case constants.EVENTS.HOST_TARGET: {
-      const message = parsers.hostTargetMessage(preMessage)
-      this.emit(`${message.command}/${channel}`, message)
+      message = parsers.hostTargetMessage(preMessage)
+      eventName = `${message.command}/${channel}`
       break
     }
+
     case constants.EVENTS.MODE: {
-      const message = parsers.modeMessage(preMessage)
+      message = parsers.modeMessage(preMessage)
+      eventName = `${message.command}/${channel}`
 
       if (message.username === this.userState.username) {
         const channelState = this.getChannelState(channel)
@@ -500,60 +514,64 @@ function handleMessage(baseMessage) {
           },
         })
       }
-
-      this.emit(`${message.command}/${channel}`, message)
       break
     }
 
     case constants.EVENTS.GLOBAL_USER_STATE: {
-      const message = parsers.globalUserStateMessage(preMessage)
+      message = parsers.globalUserStateMessage(preMessage)
       this.userState = message.tags
-      this.emit(message.command, message)
       break
     }
+
     case constants.EVENTS.USER_STATE: {
-      const message = parsers.userStateMessage(preMessage)
+      message = parsers.userStateMessage(preMessage)
+      eventName = `${message.command}/${channel}`
+
       this.setChannelState(channel, {
         ...this.getChannelState(channel),
         userState: message.userState,
       })
-      this.emit(`${message.command}/${channel}`, message)
       break
     }
+
     case constants.EVENTS.ROOM_STATE: {
-      const message = parsers.roomStateMessage(preMessage)
+      message = parsers.roomStateMessage(preMessage)
+      eventName = `${message.command}/${channel}`
+
       this.setChannelState(channel, {
         ...this.getChannelState(channel),
         roomState: message.roomState,
       })
-      this.emit(`${message.command}/${channel}`, message)
       break
     }
+
     case constants.EVENTS.NOTICE: {
-      const message = parsers.noticeMessage(preMessage)
-      this.emit(`${message.command}/${message.event}/${channel}`, message)
+      message = parsers.noticeMessage(preMessage)
+      eventName = `${message.command}/${message.event}/${channel}`
       break
     }
+
     case constants.EVENTS.USER_NOTICE: {
-      const message = parsers.userNoticeMessage(preMessage)
-      this.emit(`${message.command}/${message.event}/${channel}`, message)
+      message = parsers.userNoticeMessage(preMessage)
+      eventName = `${message.command}/${message.event}/${channel}`
       break
     }
+
     case constants.EVENTS.PRIVATE_MESSAGE: {
-      const message = parsers.privateMessage(preMessage)
-      const eventName = message.event
+      message = parsers.privateMessage(preMessage)
+      eventName = message.event
         ? `${message.command}/${message.event}/${channel}`
         : `${message.command}/${channel}`
-      this.emit(eventName, message)
       break
     }
 
     default: {
       const command = chatUtils.getEventNameFromMessage(preMessage)
-      const eventName = channel === '#' ? command : `${command}/${channel}`
-      this.emit(eventName, preMessage)
+      eventName = channel === '#' ? command : `${command}/${channel}`
     }
   }
+
+  this.emit(eventName, message)
 }
 
 function handleDisconnect() {


Test patch:
diff --git a/src/Chat/__tests__/__snapshots__/index.test.js.snap b/src/Chat/__tests__/__snapshots__/index.test.js.snap
index 4015b35..0ab5a86 100644
--- a/src/Chat/__tests__/__snapshots__/index.test.js.snap
+++ b/src/Chat/__tests__/__snapshots__/index.test.js.snap
@@ -99,7 +99,7 @@ Array [
       "_raw": ":ronni!ronni@ronni.tmi.twitch.tv JOIN #dallas",
       "channel": "#dallas",
       "command": "JOIN",
-      "isSelf": false,
+      "isSelf": true,
       "message": undefined,
       "tags": Object {},
       "timestamp": 2018-01-01T00:00:00.000Z,
@@ -231,7 +231,7 @@ Object {
   "_raw": ":ronni!ronni@ronni.tmi.twitch.tv JOIN #dallas",
   "channel": "#dallas",
   "command": "JOIN",
-  "isSelf": false,
+  "isSelf": true,
   "message": undefined,
   "tags": Object {},
   "timestamp": 2018-01-01T00:00:00.000Z,
@@ -306,7 +306,7 @@ Array [
     "channel": "#dallas",
     "command": "353",
     "event": "353",
-    "isSelf": false,
+    "isSelf": true,
     "listType": "chatters",
     "message": undefined,
     "tags": Object {},
@@ -322,7 +322,7 @@ Array [
     "channel": "#dallas",
     "command": "353",
     "event": "353",
-    "isSelf": false,
+    "isSelf": true,
     "listType": "chatters",
     "message": undefined,
     "tags": Object {},
@@ -338,7 +338,7 @@ Array [
     "channel": "#dallas",
     "command": "366",
     "event": "366",
-    "isSelf": false,
+    "isSelf": true,
     "message": "End of /NAMES list",
     "tags": Object {},
     "timestamp": 2018-01-01T00:00:00.000Z,
@@ -761,7 +761,7 @@ Object {
   "_raw": ":ronni!ronni@ronni.tmi.twitch.tv PART #dallas",
   "channel": "#dallas",
   "command": "PART",
-  "isSelf": false,
+  "isSelf": true,
   "message": undefined,
   "tags": Object {},
   "timestamp": 2018-01-01T00:00:00.000Z,