Skip to content
This repository has been archived by the owner on Nov 10, 2022. It is now read-only.

Commit

Permalink
feat: add update-user-color event
Browse files Browse the repository at this point in the history
  • Loading branch information
severo committed Jan 21, 2020
1 parent 912c746 commit 4922148
Show file tree
Hide file tree
Showing 11 changed files with 309 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/domain/events/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export class Event {

// static readonly ListRooms = 'list-rooms'
static readonly UpdateUserName = 'update-user-name'
// static readonly UpdateUserColor = 'update-user-color'
static readonly UpdateUserColor = 'update-user-color'

static readonly InternalServerError = 'internal-server-error'
// static readonly GuestsList = 'guests-list'
Expand Down
2 changes: 1 addition & 1 deletion src/domain/events/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export * from './connection.event'

// export * from "./list.rooms.event";
export * from './update.user.name.event'
// export * from "./update.user.color.event";
export * from './update.user.color.event'

export * from './internal.server.error.event'
// export * from "./guests.list.event";
21 changes: 21 additions & 0 deletions src/domain/events/update.user.color.event.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { expect } from 'chai'
import { UpdateUserColorEvent } from './update.user.color.event'

describe('Events', () => {
describe('UpdateUserColorEvent', () => {
it("should have 'update-user-color' event as name", () => {
expect(UpdateUserColorEvent.eventName).to.equal('update-user-color')
})

it('should initialize event data', () => {
// arrange
let data = { color: '#888444' }

// act
let event = new UpdateUserColorEvent(data)

// assert
expect(event.data.color).to.equal('#888444')
})
})
})
6 changes: 6 additions & 0 deletions src/domain/events/update.user.color.event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Event } from './event'

export class UpdateUserColorEvent {
static readonly eventName: string = Event.UpdateUserColor
constructor(public readonly data: { color: string }) {}
}
1 change: 1 addition & 0 deletions src/domain/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import nanoid from 'nanoid'
import rnd from 'randomcolor'

// Validation
// TODO: remove, or merge, with src/shared/validation?
const nameSchema = Joi.string().min(1)
const colorSchema = Joi.string().pattern(
new RegExp('^#(?:[0-9a-fA-F]{3}){1,2}$')
Expand Down
65 changes: 65 additions & 0 deletions src/shared/validation/guard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,71 @@ describe('Shared', () => {
})
})

describe('throwIfStringNotAnHexColor', () => {
it('should throw for undefined string', () => {
expect(() =>
Guard.throwIfStringNotAnHexColor(undefined, message)
).to.throw(message)
})

it('should throw for whitespace string', () => {
expect(() => Guard.throwIfStringNotAnHexColor(' ', message)).to.throw(
message
)
})

it('should throw for empty string', () => {
expect(() => Guard.throwIfStringNotAnHexColor('', message)).to.throw(
message
)
})

it('should throw for null string', () => {
expect(() => Guard.throwIfStringNotAnHexColor(null, message)).to.throw(
message
)
})

it('should throw for an invalid color string', () => {
expect(() => Guard.throwIfStringNotAnHexColor('1A3', message)).to.throw(
message
)
expect(() =>
Guard.throwIfStringNotAnHexColor('1A34B6', message)
).to.throw(message)
expect(() =>
Guard.throwIfStringNotAnHexColor('1A34b6', message)
).to.throw(message)
expect(() =>
Guard.throwIfStringNotAnHexColor('1A34b608', message)
).to.throw(message)
expect(() =>
Guard.throwIfStringNotAnHexColor('blue', message)
).to.throw(message)
expect(() =>
Guard.throwIfStringNotAnHexColor('rgb(0,0,0)', message)
).to.throw(message)
expect(() =>
Guard.throwIfStringNotAnHexColor('rgba(0,0,0,100)', message)
).to.throw(message)
expect(() =>
Guard.throwIfStringNotAnHexColor('#1a34B608', message)
).to.throw(message)
})

it('should not throw for a 3 or 6 digits-long hexadecimal color string', () => {
expect(() =>
Guard.throwIfStringNotAnHexColor('#1A3', message)
).to.not.throw(message)
expect(() =>
Guard.throwIfStringNotAnHexColor('#1A34B6', message)
).to.not.throw(message)
expect(() =>
Guard.throwIfStringNotAnHexColor('#1a34B6', message)
).to.not.throw(message)
})
})

describe('validate', () => {
it('should throw for truthy condition', () => {
expect(() => Guard.validate(true, message)).to.throw(message)
Expand Down
7 changes: 7 additions & 0 deletions src/shared/validation/guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ export class Guard {
)
}

static throwIfStringNotAnHexColor(value: string, message: string) {
this.throwIfConditionIsTruthy(
RegExp('^#(?:[0-9a-fA-F]{3}){1,2}$').test(value) === false,
message
)
}

static validate(condition: boolean, message: string) {
this.throwIfConditionIsTruthy(condition, message)
}
Expand Down
3 changes: 3 additions & 0 deletions src/socket.io/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export class Constants {
static dataIsRequired: string = 'Parameter data is required'
static dataNameIsRequired: string = 'Parameter <Object>.name is required'
static dataColorIsRequired: string = 'Parameter <Object>.color is required'
static dataColorHasNotHexFormat: string =
'Parameter <Object>.color has not an hexadecimal color format'
}
155 changes: 152 additions & 3 deletions src/socket.io/socket.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
// ConnectionEvent,
// InternalServerErrorEvent,
UpdateUserNameEvent,
UpdateUserColorEvent,
} from '../domain/events'

const socketUrl: string = 'http://localhost:5000'
Expand Down Expand Up @@ -100,7 +101,6 @@ describe('Server', () => {

it('should log info message for empty name and updated should be false', (done: Function) => {
// arrange
const expectedParameter: string = 'name'
const updateUserNameEventArgs: UpdateUserNameEventArgs = { name: '' }
const updateUserNameEvent = new UpdateUserNameEvent(
updateUserNameEventArgs
Expand All @@ -124,12 +124,12 @@ describe('Server', () => {
expect(value.error).to.have.property('name', 'Error')
expect(value.error).to.have.property(
'message',
`Parameter <Object>.${expectedParameter} is required`
`Parameter <Object>.name is required`
)

const logs = mockLogger.getInfoLogs()
logs.should.include.something.that.equals(
`User name could not be updated - Parameter <Object>.${expectedParameter} is required`
`User name could not be updated - Parameter <Object>.name is required`
)
done()
})
Expand Down Expand Up @@ -169,6 +169,155 @@ describe('Server', () => {
})
})

describe('update-user-color', () => {
it('should log info message for empty data and updated should be false', (done: Function) => {
// arrange
const updateUserColorEventArgs: undefined = undefined
const updateUserColorEvent = new UpdateUserColorEvent(
updateUserColorEventArgs
)

new Promise(resolve =>
client.on('connect', () => {
// act
client.emit(
UpdateUserColorEvent.eventName,
updateUserColorEvent.data,
(value: UpdateUserColorAckArgs) => resolve(value)
)
})
)
.then((value: UpdateUserColorAckArgs) => {
// assert
expect(value).to.not.be.undefined
expect(value).to.have.property('updated', false)
expect(value).to.have.property('error')
expect(value.error).to.have.property('name', 'Error')
expect(value.error).to.have.property(
'message',
`Parameter data is required`
)

const logs = mockLogger.getInfoLogs()
logs.should.include.something.that.equals(
`User color could not be updated - Parameter data is required`
)
done()
})
.catch(e => done(e))
})

it('should log info message for empty color and updated should be false', (done: Function) => {
// arrange
const updateUserColorEventArgs: UpdateUserColorEventArgs = {
color: '',
}
const updateUserColorEvent = new UpdateUserColorEvent(
updateUserColorEventArgs
)

new Promise(resolve =>
client.on('connect', () => {
// act
client.emit(
UpdateUserColorEvent.eventName,
updateUserColorEvent.data,
(value: UpdateUserColorAckArgs) => resolve(value)
)
})
)
.then((value: UpdateUserColorAckArgs) => {
// assert
expect(value).to.not.be.undefined
expect(value).to.have.property('updated', false)
expect(value).to.have.property('error')
expect(value.error).to.have.property('name', 'Error')
expect(value.error).to.have.property(
'message',
`Parameter <Object>.color is required`
)

const logs = mockLogger.getInfoLogs()
logs.should.include.something.that.equals(
`User color could not be updated - Parameter <Object>.color is required`
)
done()
})
.catch(e => done(e))
})

it('should log info message for invalid color and updated should be false', (done: Function) => {
// arrange
const updateUserColorEventArgs: UpdateUserColorEventArgs = {
color: '1235g',
}
const updateUserColorEvent = new UpdateUserColorEvent(
updateUserColorEventArgs
)

new Promise(resolve =>
client.on('connect', () => {
// act
client.emit(
UpdateUserColorEvent.eventName,
updateUserColorEvent.data,
(value: UpdateUserColorAckArgs) => resolve(value)
)
})
)
.then((value: UpdateUserColorAckArgs) => {
// assert
expect(value).to.not.be.undefined
expect(value).to.have.property('updated', false)
expect(value).to.have.property('error')
expect(value.error).to.have.property('name', 'Error')
expect(value.error).to.have.property(
'message',
`Parameter <Object>.color has not an hexadecimal color format`
)

const logs = mockLogger.getInfoLogs()
logs.should.include.something.that.equals(
`User color could not be updated - Parameter <Object>.color has not an hexadecimal color format`
)
done()
})
.catch(e => done(e))
})

it('should log info message for correct name, updated should be true and error should not exist', (done: Function) => {
// arrange
const updateUserColorEventArgs: UpdateUserColorEventArgs = {
color: '#123BCA',
}
const updateUserColorEvent = new UpdateUserColorEvent(
updateUserColorEventArgs
)

new Promise(resolve =>
client.on('connect', () => {
// act
client.emit(
UpdateUserColorEvent.eventName,
updateUserColorEvent.data,
(value: UpdateUserColorAckArgs) => resolve(value)
)
})
)
.then((value: UpdateUserColorAckArgs) => {
// assert
expect(value).to.not.be.undefined
expect(value).to.have.property('updated', true)
expect(value).to.not.have.property('error')

const logs = mockLogger.getInfoLogs()
logs.should.include.something.that.equals(`User color updated`)
done()
})
.catch(e => done(e))
})
})

//
//
// it("should emit 'internal-server-error' when name is not defined", (done: Function) => {
Expand Down
39 changes: 39 additions & 0 deletions src/socket.io/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ConnectionEvent,
// InternalServerErrorEvent,
UpdateUserNameEvent,
UpdateUserColorEvent,
} from '../domain/events'
import { User } from '../domain'

Expand Down Expand Up @@ -55,6 +56,44 @@ class Socket {
ack({ updated: true })
}

socket.on(
UpdateUserColorEvent.eventName,
(data: UpdateUserColorEventArgs, ack: UpdateUserColorAck) => {
try {
updateUserColor(data, ack)
} catch (error) {
this.log.info('User color could not be updated', error.message)
ack({
updated: false,
error: this.toException(error),
})
}
}
)

const updateUserColor = (
data: UpdateUserColorEventArgs,
ack: UpdateUserColorAck
) => {
Guard.throwIfObjectUndefined(data, Constants.dataIsRequired)
Guard.throwIfStringNotDefinedOrEmpty(
data.color,
Constants.dataColorIsRequired
)
Guard.throwIfStringNotAnHexColor(
data.color,
Constants.dataColorHasNotHexFormat
)
socketUser.color = data.color

// TODO: emit list-room-guests to all the rooms where user is logged
// TODO: alternative: send mutation : room-guest-name-updated
// this.emitLoggedUsersToRoom(socket, room)

this.log.info('User color updated')
ack({ updated: true })
}

// const roomJoin = (data: RoomJoinEventArgs, ack: RoomJoinAck) => {
// Guard.throwIfObjectUndefined(data, Constants.dataIsRequired)
// Guard.throwIfStringNotDefinedOrEmpty(
Expand Down
Loading

0 comments on commit 4922148

Please sign in to comment.