Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/conversations #480

Merged
merged 22 commits into from
Mar 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
aa2c8c1
VIDEO 3731 Conversations UI - create chat window (#421)
olipyskoty Feb 19, 2021
9849c28
Video 4078 add flip camera button to mobile menu (#433)
olipyskoty Feb 25, 2021
23b9e8d
Merge branch 'master' into feature/conversations
Feb 25, 2021
045aee0
Video 3730 add conversation hooks (#438)
Mar 2, 2021
be26af4
Video 3732 Conversations UI - create message components (#441)
olipyskoty Mar 3, 2021
925dd39
Add links to TextMessage component (#446)
Mar 3, 2021
abd0f1b
Merge branch 'master' into feature/conversations
Mar 5, 2021
89d98fd
Add new server (#443)
Mar 11, 2021
e18f291
Video 3728 Conversations UI - add input field and send button (#451)
olipyskoty Mar 11, 2021
a56465f
Chat notification (#454)
Mar 15, 2021
92e1131
Video-4525 loading screen (#461)
olipyskoty Mar 24, 2021
86f33a3
Video 4454 Conversations UI - message list scrolling (#467)
olipyskoty Mar 25, 2021
475014d
Update MessageList component to change how messages are grouped (#469)
Mar 25, 2021
82e4928
Video 3888 file input for conversations (#458)
Mar 26, 2021
8cbfaa2
Update readme to add information about the chat feature and conversat…
seancoleman2 Mar 30, 2021
5ca5c00
Cross browser fixes (#472)
Mar 30, 2021
f382369
Video 3727 - cypress testing (#473)
olipyskoty Mar 30, 2021
bd4c7c4
Merge branch 'master' into feature/conversations
Mar 31, 2021
5bc3cad
Video 4597 feature flag (#475)
Mar 31, 2021
4ebacc2
Update readme with info about twilio conversations (#476)
Mar 31, 2021
4813289
Release 0.3.0 (#479)
Mar 31, 2021
82875f4
Merge branch 'master' into feature/conversations
Mar 31, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 21 additions & 17 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- v1-deps-{{ .Branch }}-{{ checksum "package-lock.json" }}
- v1-deps-{{ .Branch }}
- v1-deps

- run: npm ci

- save_cache:
Expand All @@ -24,29 +24,33 @@ jobs:
- ~/.cache

- run:
name: "Jest Unit Tests"
name: 'Jest Unit Tests'
command: npm run test:ci
environment:
JEST_JUNIT_OUTPUT_DIR: "test-reports/jest"
JEST_JUNIT_OUTPUT_NAME: "results.xml"
JEST_JUNIT_CLASSNAME: "{classname}"
JEST_JUNIT_TITLE: "{title}"
JEST_JUNIT_OUTPUT_DIR: 'test-reports/jest'
JEST_JUNIT_OUTPUT_NAME: 'results.xml'
JEST_JUNIT_CLASSNAME: '{classname}'
JEST_JUNIT_TITLE: '{title}'

- store_artifacts:
path: coverage

- run:
name: "Eslint"
- run:
name: 'Eslint'
command: npm run lint -- --max-warnings 0

- run:
name: "Build app with Firebase auth disabled"
- run:
name: 'Check server types'
command: npm run typescript:server

- run:
name: 'Build app with Firebase auth disabled'
command: npm run build
environment:
REACT_APP_TOKEN_ENDPOINT: "http://localhost:8081/token"
REACT_APP_TOKEN_ENDPOINT: 'http://localhost:8081/token'

- run:
name: "Set environment variables for local token server (used by Cypress tests)"
- run:
name: 'Set environment variables for local token server (used by Cypress tests)'
command: |
echo TWILIO_ACCOUNT_SID=$TWILIO_ACCOUNT_SID >> .env
echo TWILIO_API_KEY_SID=$TWILIO_API_KEY >> .env
Expand All @@ -59,7 +63,7 @@ jobs:

# Rebuild app with firebase auth enabled
- run:
name: "Build app with Firebase auth enabled"
name: 'Build app with Firebase auth enabled'
command: |
echo REACT_APP_SET_AUTH=firebase >> .env
echo REACT_APP_TOKEN_ENDPOINT=$REACT_APP_TOKEN_ENDPOINT >> .env
Expand All @@ -74,7 +78,7 @@ jobs:

- persist_to_workspace:
root: .
paths:
paths:
- .

deploy:
Expand All @@ -85,7 +89,7 @@ jobs:
steps:
- attach_workspace:
at: ~/twilio-video-react-app

- run: |
echo $GCLOUD_SERVICE_KEY | gcloud auth activate-service-account --key-file=-
gcloud --quiet config set project ${GOOGLE_PROJECT_ID}
Expand All @@ -109,4 +113,4 @@ workflows:
tags:
only: /^v.*/
branches:
ignore: /.*/
ignore: /.*/
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ TWILIO_ACCOUNT_SID=AC00000000000000000000000000000000
TWILIO_API_KEY_SID=SK00000000000000000000000000000000
TWILIO_API_KEY_SECRET=00000000000000000000000000000000

# TWILIO_CONVERSATIONS_SERVICE_SID must be populated in order to use the chat feature in the app.
# Note: this variable is not required if REACT_APP_DISABLE_TWILIO_CONVERSATIONS is set to 'true'.
TWILIO_CONVERSATIONS_SERVICE_SID=IS00000000000000000000000000000000

# Un-comment the following line to disable the Twilio Conversations functionality in the app.
# REACT_APP_DISABLE_TWILIO_CONVERSATIONS=true

# Un-comment the following line to use a custom endpoint for obtaining tokens. Defaults to /token
# REACT_APP_TOKEN_ENDPOINT=https://example.com/token

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ yarn-error.log*

test-reports
junit.xml
serviceAccountKey.json
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.3.0

### New Feature

- This release adds an in-room chat feature. This chat feature allows users to send and receive textual messages and files while connected to a Twilio Video room. This feature is powered by the [Twilio Conversations API](https://www.twilio.com/conversations-api). For more information, please see this [blog post](https://www.twilio.com/blog/open-source-video-chat-app-reactjs-conversations-api).

## 0.2.4

### Bugfixes
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2020 Twilio Inc.
Copyright 2021 Twilio Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
81 changes: 44 additions & 37 deletions README.md

Large diffs are not rendered by default.

29 changes: 9 additions & 20 deletions app.yaml
Original file line number Diff line number Diff line change
@@ -1,23 +1,12 @@
runtime: python27
api_version: 1
threadsafe: true
runtime: nodejs12

handlers:
- url: /static
secure: always
static_dir: build/static

- url: /(.*\.(json|ico|js|txt|png))$
secure: always
static_files: build/\1
upload: build/.*\.(json|ico|js|txt|png)$
entrypoint: npm run server

- url: /.well-known/apple-app-site-association
secure: always
static_files: build/.well-known/apple-app-site-association
upload: build/.well-known/apple-app-site-association
env_variables:
REACT_APP_SET_AUTH: 'firebase'

- url: .*
secure: always
static_files: build/index.html
upload: build/index.html
handlers:
- url: /.*
secure: always
redirect_http_response_code: 301
script: auto
70 changes: 70 additions & 0 deletions cypress/integration/twilio-video.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,76 @@ context('A video app user', () => {
it('should be able to hear the other participant', () => {
cy.getParticipant('test1').shouldBeMakingSound();
});

describe('the chat feature', () => {
// Before we test the chat feature, we want to open the chat window and send enough messages
// to make the message list taller than its container so that we can test the scrolling behavior:
before(() => {
cy.get('[data-cy-chat-button]').click();
// Create an array with 15 values, then send a message when looping over each of them:
Array(15)
.fill(true)
.forEach((_, i) => {
cy.task('sendAMessage', {
name: 'test1',
message: 'welcome to the chat! - ' + i,
});
});
// Wait 1 second for the above to complete:
cy.wait(1000);
cy.contains('welcome to the chat! - 14');
});

after(() => {
cy.get('[data-cy-chat-button]').click();
});

it('should see "1 new message" button when not scrolled to bottom of chat and a new message is received', () => {
cy.get('[data-cy-message-list-inner-scroll]').scrollTo(0, 0);
cy.task('sendAMessage', { name: 'test1', message: 'how is it going?' });
cy.contains('1 new message').should('be.visible');
});

it('should scroll to bottom of chat when "1 new message button" is clicked on', () => {
cy.get('[data-cy-message-list-inner-scroll]').scrollTo(0, 0);
cy.task('sendAMessage', { name: 'test1', message: 'Ahoy!' });
cy.contains('Ahoy!');
cy.get('[data-cy-new-message-button]')
.should('be.visible')
.click();
cy.get('[data-cy-message-list-inner-scroll]')
.contains('Ahoy!')
.should('be.visible');

// Here we are checking if the chat window has scrolled all the way to the bottom.
// The following will be true if the scrolling container's scrollHeight property
// is equal to its 'scrollTop' plus its 'clientHeight' properties:
cy.get('[data-cy-message-list-inner-scroll]').should($el => {
expect($el.prop('scrollHeight')).to.equal($el.prop('scrollTop') + $el.prop('clientHeight'));
});
});

it('should not see "1 new message" button when manually scroll to bottom of chat after receiving new message', () => {
cy.get('[data-cy-message-list-inner-scroll]').scrollTo(0, 0);
cy.task('sendAMessage', { name: 'test1', message: 'chatting is fun!' });
cy.get('[data-cy-new-message-button]').should('be.visible');
cy.get('[data-cy-message-list-inner-scroll]').scrollTo('bottom');
cy.get('[data-cy-new-message-button]').should('not.be.visible');
cy.get('[data-cy-message-list-inner-scroll]')
.contains('chatting is fun!')
.should('be.visible');
});

it('should auto-scroll to bottom of chat when already scrolled to bottom and a new message is received', () => {
cy.get('[data-cy-message-list-inner-scroll]').scrollTo('bottom');
cy.task('sendAMessage', { name: 'test1', message: 'what a wonderful day!' });
cy.contains('what a wonderful day!');
// Check if chat window is scrolled to the bottom:
cy.get('[data-cy-message-list-inner-scroll]').should($el => {
expect($el.prop('scrollHeight')).to.equal($el.prop('scrollTop') + $el.prop('clientHeight'));
});
});
});
});

describe('when entering an empty room that three participants will join', () => {
Expand Down
7 changes: 7 additions & 0 deletions cypress/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ module.exports = (on, config) => {
delete participants[name];
return Promise.resolve(null);
},
sendAMessage: async ({ message, name }) => {
const page = participants[name];
await page.click('[data-cy-chat-button]');
await page.type('[data-cy-chat-input]', message);
await page.click('[data-cy-send-message-button]');
return Promise.resolve(null);
},
};
on('task', participantFunctions);
};
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = {
roots: ['<rootDir>/src'],
roots: ['<rootDir>/src', '<rootDir>/server'],
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
Expand Down
Loading