+
+
+ User Stories and Conditions of Satisfaction
+
+
+
+
+
+
+
+ Introduction
+
+
+
+
+
+
This activity will give you practice with using user stories to solicit and document user requirements, refining them into conditions of satisfaction, and assigning priorities.
Choose one of the two scenarios (as required by your instructor):
+
+
+
+ Scenario 1
+
+
+
+
+
+
Imagine that the State of Massachusetts is your client and you are the lead of a development team. You have already walked your client through the material in the tutorial, and together you have developed the following user story:
+
+
+
As a resident of the State of Massachusetts, I would like to obtain my mail-in ballot so that I can cast my vote by mail.
+
+
+
+
+ Requirements for this activity
+
+
+
+
+
+
+
Write down at least 3 questions that you should ask the client before beginning to write conditions of satisfaction for this user story.
+
Write at least 3 conditions of satisfaction with appropriate priority
+
Then write 3 bad examples of conditions of satisfaction, and briefly say why they are bad.
+
+
+
When you are done, submit your work as required by your instructor. This may vary from section to section.
+
+
+
+ Scenario 2
+
+
+
+
+
+
Imagine that you are the owner of a restaurant, and your consultant has convinced you that you need to have a web site. You and they have walked through the material in Module 01 and the Tutorial on User Stories. Your consultant is also a fan of “systems thinking”, by which they mean looking at a problem from many different points of view.
+
+
+
+ Requirements for this activity
+
+
+
+
+
+
+
Identify at least 3 different roles representing different points of view
+
+
Choose one of those roles and write down at least 3 different user stories for that participant. These should be of the form
+
+
As a <role> I want to <some property of the system> so that I can <receive some benefit>
+
+
For one of those user stories, write 3 conditions of satisfaction with appropriate priority.
+
+
+
When you are done, submit your work as required by your instructor. This may vary from section to section.
We will gain experience improving test suites using two adequacy criteria: line coverage and mutation coverage. The instructions reference line numbers in transcriptManager.ts. Do not change that file while you are following along, or else you may find that the line referenced do not match what you see.
+
+
As usual, download the starter code and run npm install.
+
+
Then, follow the instructions given in the README.md file
In this activity, you will do a simple example to help you recognize failure of the five code-level design principles
+
+
+
+ Step 0: Getting started
+
+
+
+
+
Start by downloading the (Starter Code).
+Run npm install to download the dependencies for this project, and then open it in your IDE of choice.
+Run npm run test to run the tests of the existing code (or run the script in VSC). You will see that the tests pass.
+
+
+
+ The Problem
+
+
+
+
+
+
Your team is writing a simulator for a traffic light in a large city. Whitley, an intern in your group, has written the code in TrafficLight.ts, and the tests in TrafficLight.test.ts
+
+
Your team leader, Adrian, has asked you to critique Whitley’s code based on the Five Code-Level Design Principles. Adrian says that he has already received some feedback from the client, who complained that not all traffic lights change when they are expected (they expect all lights to change at the same time, and for the red to be 20, yellow 5 and green 15 seconds). Moreover, the lights in different intersections are not synchronized, so that cars have to stop at every intersection.
+
+
+
+ Part 1: Critique Whitley’s code.
+
+
+
+
+
+
In a text file, list several ways in which Whitley’s code violates the 5 Principles.
+
+
+
+ Part 2: Improve Whitley’s code
+
+
+
+
+
+
Write a new file, called betterTrafficLight.ts, which Principles, and addresses some of the problems raised by the customer. Test your code by changing TrafficLight.test.ts to import from betterTrafficLight.ts
+
+
+
+ Part 3: Critique your own code
+
+
+
+
+
+
Now look at your own code. Based on your experience with traffic lights, list 3 assumptions that your code makes about the behavior of traffic lights in a large city. In what ways is the client likely to be unhappy with the assumptions you made? (Stretch goal: how could you redesign your code to make it more flexible?)
+
+
+
+ Submit your work
+
+
+
+
+
+
Instructions for submitting this activity will appear in Canvas.
2024-01-23: Migrate ts-node implementation to tsx for node 18.18 compatibility
+
+
+
+
+ Instructions to install Node-Version
+
+
+
+
+
+
nvm install 18.18
+
nvm use 18.18
+
+
+
+
+ Instructions
+
+
+
+
+
+
To run it on your computer, run npm install to fetch the dependencies for the project, and then run npm run demo, which should produce the output like the following:
+
Current conditions: 80F degrees and 65% humidity
+Avg/max/min temperature = 80/80/0
+Heat Index: 82.95535063710001
+Forecast: Improving weather on the way!
+Current conditions: 82F degrees and 70% humidity
+Avg/max/min temperature = 81/82/0
+Heat Index: 86.90123306385205
+Forecast: Watch out for cooler, rainy weather
+Current conditions: 78F degrees and 90% humidity
+Avg/max/min temperature = 80/82/0
+Heat Index: 83.64967139559604
+Forecast: More of the same
+
+
+
There is a lot to be improved from this design. Modify this code so that it uses the observer pattern, with each of the various display classes as
+the observers, and the WeatherData as the subject object.
+
+
A high-level sketch of this design is:
+
+
Create a WeatherDataObserver interface, which defines your update method
+
In WeatherData, create an observers array in WeatherData along with methods to register and de-register observers. Add code to notify the observers of updates when the weather data updates.
+
Modify each of CurrentConditionsDisplay, ForecastDisplay, HeatIndexDisplay and StatisticsDisplay to be implementors of the new observer interface. These display classes should display their information whenever the weather data is updated.
+
Modify WeatherStation, so that it creates the XXXDisplays, and subscribes them to the WeatherData
+
Update WeatherData.measurementsChanged to notify its observers of the update
+
Compare the output of your new program to the output you got by running the original version. Are the lines printed in the same order? Why or why not?
+
Can you modify the code so that the various XXXDisplay classes are all implementations of the same interface? Why might or might not this be a good idea?
+
+
+
When you are done, run npm run zip to create a zip archive with your code.
+
+
This activity is based on the running example in Chapter 2 of “Head First Design Patterns, 2nd Edition” by Robson and Freeman.
Practice applying asynchronous programming concepts: promises, async/await
+
Experiment with applying different ordering constraints in asynchronous code
+
+
+
+
+ Overview
+
+
+
+
+
In this activity, you will experiment with asynchronous programming constructs in TypeScript.
+
+
+
+ Getting started
+
+
+
+
+
Download starter Code
+Run npm install to download the dependencies for this project, and then open it in your IDE of choice.
+Run npm run client to run the client as-is, the output should be something like:
+
+
+ Stringing together many async calls: bulk importing grades
+
+
+
+
+
Your task is to write a new, async function, importGrades, which takes in input of the type ImportTranscript[].
+importGrades should create a student record for each ImportTranscript, and then post the grades for each of those students.
+After posting the grades, it should fetch the transcripts for each student and return an array of transcripts.
+
+
You should implement importGrades in the file examples.ts - note that there is already a function stub there.
+As you get started, examine the transcript server client in client.ts, and take note of the API calls that are available to you.
+
+
Here is the type definition for ImportTranscript and its dependencies:
Insert a student, insert each of their grades (in order), then insert the next student, then their grades, etc. until all students are inserted, then fetch transcripts
+
Insert a student, then insert each of their grades (in order), then fetch their transcript. Do this set of operations asynchronously (concurrently) for all students
+
Insert a student, then insert each of their grades asynchronously (concurrently). After all students have all of their grades submitted, fetch all fo the transcripts asynchronously (concurrently)
This activity is designed to give you practice with React. You will enhance the ToDo app that was discussed in lecture.
+
+
+
+ Steps
+
+
+
+
+
+
To get started, download the starter Code. Run the command npm install, and then npm run dev. The development server should start, and If you open your browser it will start running the app in app/page.tsx If your browser does not open up in the todo app, modify app/page.tsx to point to ./Apps/ToDoApp
+
+
In the ToDoApp, make the following three enhancements:
+
+
+
Currently the “priority” field will accept any value. Modify it so that the priority must be a number. (Hint: NumberInput is your friend)
+
Add a button that will sort the todo items by priority, lowest number first
+
Add an entry field that will take a number and delete all the todo items with priorities greater than that number. (We are assuming that priority 1 means the thing that has to be done first.)
+
+
+
When you are done, submit your work as required by your instructor. This may vary from section to section.
In this activity, you will use TSOA to build a REST client for our transcript database.
+
+
Requirement: node -version = @16 0r @17
+
+
As usual, download the starter code and run npm install.
+
+
Then, run npm start to generate the OpenAPI specification, server boilerplate, and start the development server.
+This command will automatically reload the server as you change files in this project.
+To stop the server, press control-C in the terminal.
You should now see a “Swagger” transcript-server-openapi documentation page, with a few API endpoints defined. Expand the “GET /transcripts” endpoint, click “Try it out”, and then “Execute”. Now, the field “Response Body” should have text in it like:
This demonstrates that this endpoint of your REST API is functional. In the rest of the activity, you will implement the remainder of the routes. Details are in the README page of the starter code.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Activities/assets/continuous_dev/gha-secrets-twilio.png b/Activities/assets/continuous_dev/gha-secrets-twilio.png
new file mode 100644
index 00000000..c5e40168
Binary files /dev/null and b/Activities/assets/continuous_dev/gha-secrets-twilio.png differ
diff --git a/Activities/assets/continuous_dev/heroku-account-settings-menu.png b/Activities/assets/continuous_dev/heroku-account-settings-menu.png
new file mode 100644
index 00000000..386abbcd
Binary files /dev/null and b/Activities/assets/continuous_dev/heroku-account-settings-menu.png differ
diff --git a/Activities/assets/continuous_dev/heroku-settings-expanded.png b/Activities/assets/continuous_dev/heroku-settings-expanded.png
new file mode 100644
index 00000000..b5893b93
Binary files /dev/null and b/Activities/assets/continuous_dev/heroku-settings-expanded.png differ
diff --git a/Activities/assets/continuous_dev/heroku-settings.png b/Activities/assets/continuous_dev/heroku-settings.png
new file mode 100644
index 00000000..2da7261f
Binary files /dev/null and b/Activities/assets/continuous_dev/heroku-settings.png differ
diff --git a/Activities/assets/continuous_dev/netlify-build-settings.png b/Activities/assets/continuous_dev/netlify-build-settings.png
new file mode 100644
index 00000000..86d9c148
Binary files /dev/null and b/Activities/assets/continuous_dev/netlify-build-settings.png differ
diff --git a/Activities/assets/continuous_dev/netlify-done.png b/Activities/assets/continuous_dev/netlify-done.png
new file mode 100644
index 00000000..d821eecc
Binary files /dev/null and b/Activities/assets/continuous_dev/netlify-done.png differ
diff --git a/Activities/git-placeholder.txt b/Activities/git-placeholder.txt
new file mode 100644
index 00000000..2d6401c9
--- /dev/null
+++ b/Activities/git-placeholder.txt
@@ -0,0 +1 @@
+Placeholder file to force git to create a folder here.
\ No newline at end of file
diff --git a/Activities/module02-tdd-transcript-activity.zip b/Activities/module02-tdd-transcript-activity.zip
new file mode 100644
index 00000000..71aecbf3
Binary files /dev/null and b/Activities/module02-tdd-transcript-activity.zip differ
diff --git a/Activities/module03-test-adequacy.zip b/Activities/module03-test-adequacy.zip
new file mode 100644
index 00000000..3579eb46
Binary files /dev/null and b/Activities/module03-test-adequacy.zip differ
diff --git a/Activities/module04-traffic-light-activity.zip b/Activities/module04-traffic-light-activity.zip
new file mode 100644
index 00000000..d912e95e
Binary files /dev/null and b/Activities/module04-traffic-light-activity.zip differ
diff --git a/Activities/module05-design-pattern-activity-weatherstation.zip b/Activities/module05-design-pattern-activity-weatherstation.zip
new file mode 100644
index 00000000..42da8a9b
Binary files /dev/null and b/Activities/module05-design-pattern-activity-weatherstation.zip differ
diff --git a/Activities/module06-async_activity.zip b/Activities/module06-async_activity.zip
new file mode 100644
index 00000000..53848a30
Binary files /dev/null and b/Activities/module06-async_activity.zip differ
diff --git a/Activities/module08-react-activity.zip b/Activities/module08-react-activity.zip
new file mode 100644
index 00000000..1acc43b6
Binary files /dev/null and b/Activities/module08-react-activity.zip differ
diff --git a/Activities/module11-rest-transcript-activity.zip b/Activities/module11-rest-transcript-activity.zip
new file mode 100644
index 00000000..94b5ee59
Binary files /dev/null and b/Activities/module11-rest-transcript-activity.zip differ
diff --git a/Activities/week1-user-stories-solutions-Spring 2024.txt b/Activities/week1-user-stories-solutions-Spring 2024.txt
new file mode 100644
index 00000000..c7a88fc7
--- /dev/null
+++ b/Activities/week1-user-stories-solutions-Spring 2024.txt
@@ -0,0 +1,43 @@
+Roles:
+
+Owner/Manager
+Prospective Customer
+Chef
+
+
+* As Owner/Manager I want
+
+to be able to add and delete menu items so I can change the menu easily (Essential)
+
+to be able to change the price of a menu item so I can respond to changing
+supply costs. (Essential)
+
+to have pictures of my dises on the web site, so customers will see how good
+our food looks (Desirable)
+
+
+* As a Prospective Customer, I want
+
+the web site to show what is on the menu today, so I can see if they have
+what I want (Essential)
+
+to have nice pictures of the restaurant, so I can get an idea of whether I
+want to go there. (Essential)
+
+to be easy to navigate to different portions of the menu, so I can easily
+distinguish appetizers/main dishes/desserts, etc. (Desirable)
+
+to have possible substitutions listed, so I can know whether a dish can be
+modified to meet my dietary needs. (Extension)
+
+* As a chef, I want
+
+the web site to keep track of how many of each dish was ordered, so I can
+know how much of each ingredient to buy. (Essential? Desirable?)
+
+the web site to show customers what substitutions are possible, so I can keep track of
+what variations I need to prepare for. (Extension)
+
+
+
+
diff --git a/Assignments/git-fodder.txt b/Assignments/git-fodder.txt
new file mode 100644
index 00000000..7b57bd29
--- /dev/null
+++ b/Assignments/git-fodder.txt
@@ -0,0 +1 @@
+some text
diff --git a/Assignments/ip1/ip1-handout.zip b/Assignments/ip1/ip1-handout.zip
new file mode 100644
index 00000000..cd7c94cb
Binary files /dev/null and b/Assignments/ip1/ip1-handout.zip differ
diff --git a/Assignments/ip1/npm-warnings.jpg b/Assignments/ip1/npm-warnings.jpg
new file mode 100644
index 00000000..cb73aca9
Binary files /dev/null and b/Assignments/ip1/npm-warnings.jpg differ
diff --git a/Assignments/ip2/GamesArea.test.tsx b/Assignments/ip2/GamesArea.test.tsx
new file mode 100644
index 00000000..430e29e0
--- /dev/null
+++ b/Assignments/ip2/GamesArea.test.tsx
@@ -0,0 +1,373 @@
+import { ChakraProvider } from '@chakra-ui/react';
+import { render, screen } from '@testing-library/react';
+import { mock, mockReset } from 'jest-mock-extended';
+import { nanoid } from 'nanoid';
+import { act } from 'react-dom/test-utils';
+import GameAreaController, {
+ GameEventTypes,
+} from '../../../classes/interactable/GameAreaController';
+import PlayerController from '../../../classes/PlayerController';
+import TownController, * as TownControllerHooks from '../../../classes/TownController';
+import TownControllerContext from '../../../contexts/TownControllerContext';
+import { randomLocation } from '../../../TestUtils';
+import { GameArea, GameResult, GameState, InteractableType } from '../../../types/CoveyTownSocket';
+import * as ChatChannel from './ChatChannel';
+import * as ConnectFourArea from './ConnectFour/ConnectFourArea';
+import PhaserGameArea from './GameArea';
+import GamesArea, { INVALID_GAME_AREA_TYPE_MESSAGE } from './GamesArea';
+import * as Leaderboard from './Leaderboard';
+import * as TicTacToeArea from './TicTacToe/TicTacToeArea';
+import React from 'react';
+
+const mockToast = jest.fn();
+jest.mock('@chakra-ui/react', () => {
+ const ui = jest.requireActual('@chakra-ui/react');
+ const mockUseToast = () => mockToast;
+ return {
+ ...ui,
+ useToast: mockUseToast,
+ };
+});
+const mockGameArea = mock({
+ id: nanoid(),
+});
+mockGameArea.name = 'TicTacToe';
+mockGameArea.getData.mockReturnValue('TicTacToe');
+jest.spyOn(TownControllerHooks, 'useInteractable').mockReturnValue(mockGameArea);
+
+const useInteractableAreaControllerSpy = jest.spyOn(
+ TownControllerHooks,
+ 'useInteractableAreaController',
+);
+
+const CHAT_CHANNEL_TEST_ID = 'chatWindow';
+const chatChannelSpy = jest.spyOn(ChatChannel, 'default');
+chatChannelSpy.mockReturnValue();
+
+const TIC_TAC_TOE_AREA_TEST_ID = 'ticTacToeArea';
+const ticTacToeAreaSpy = jest.spyOn(TicTacToeArea, 'default');
+ticTacToeAreaSpy.mockReturnValue();
+
+const CONNECT_FOUR_AREA_TEST_ID = 'connectFourArea';
+const connectFourAreaSpy = jest.spyOn(ConnectFourArea, 'default');
+connectFourAreaSpy.mockReturnValue();
+
+const leaderboardComponentSpy = jest.spyOn(Leaderboard, 'default');
+leaderboardComponentSpy.mockReturnValue();
+
+class MockGameAreaController extends GameAreaController {
+ private _type: InteractableType = 'TicTacToeArea';
+
+ private _mockID: string;
+
+ public constructor() {
+ const id = nanoid();
+ super(id, mock>(), mock());
+ this._mockID = id;
+ }
+
+ public get id() {
+ return this._mockID;
+ }
+
+ public set id(newID: string) {
+ this._mockID = newID;
+ }
+
+ public set type(type: InteractableType) {
+ this._type = type;
+ }
+
+ toInteractableAreaModel(): GameArea {
+ if (!this._type) throw new Error('Type not set');
+ const ret = mock>();
+ ret.type = this._type;
+ return ret;
+ }
+
+ mockHistory: GameResult[] = [];
+
+ mockObservers: PlayerController[] = [];
+
+ get observers(): PlayerController[] {
+ return this.mockObservers;
+ }
+
+ get history(): GameResult[] {
+ return this.mockHistory;
+ }
+
+ public isActive(): boolean {
+ return true;
+ }
+}
+describe('GamesArea', () => {
+ // Spy on console.error and intercept react key warnings to fail test
+ let consoleErrorSpy: jest.SpyInstance;
+ beforeAll(() => {
+ // Spy on console.error and intercept react key warnings to fail test
+ consoleErrorSpy = jest.spyOn(global.console, 'error');
+ consoleErrorSpy.mockImplementation((message?, ...optionalParams) => {
+ const stringMessage = message as string;
+ if (stringMessage.includes && stringMessage.includes('children with the same key,')) {
+ throw new Error(stringMessage.replace('%s', optionalParams[0]));
+ } else if (stringMessage.includes && stringMessage.includes('warning-keys')) {
+ throw new Error(stringMessage.replace('%s', optionalParams[0]));
+ }
+ // eslint-disable-next-line no-console -- we are wrapping the console with a spy to find react warnings
+ console.warn(message, ...optionalParams);
+ });
+ });
+ afterAll(() => {
+ consoleErrorSpy.mockRestore();
+ });
+ let ourPlayer: PlayerController;
+ const townController = mock();
+ Object.defineProperty(townController, 'ourPlayer', { get: () => ourPlayer });
+ let gameAreaController = new MockGameAreaController();
+ function setGameAreaControllerID(id: string) {
+ gameAreaController.id = id;
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ mockGameArea.id = id;
+ }
+
+ beforeEach(() => {
+ ourPlayer = new PlayerController('player x', 'player x', randomLocation());
+ mockReset(townController);
+ useInteractableAreaControllerSpy.mockReturnValue(gameAreaController);
+ setGameAreaControllerID(nanoid());
+ leaderboardComponentSpy.mockClear();
+ mockToast.mockClear();
+ chatChannelSpy.mockClear();
+ });
+ function renderGamesArea() {
+ return render(
+
+
+
+
+ ,
+ );
+ }
+
+ describe('[T2.4] Rendering the correct game', () => {
+ test('If the interactableID is for a ConnectFour game, the ConnectFourGameArea should be rendered', () => {
+ gameAreaController.type = 'ConnectFourArea';
+ renderGamesArea();
+ expect(screen.getByTestId(CONNECT_FOUR_AREA_TEST_ID)).toBeInTheDocument();
+ });
+ test('If the interactableID is for a TicTacToe game, the TicTacToeGameArea should be rendered', () => {
+ gameAreaController.type = 'TicTacToeArea';
+ renderGamesArea();
+ expect(screen.getByTestId(TIC_TAC_TOE_AREA_TEST_ID)).toBeInTheDocument();
+ });
+ test('If the interactableID is NOT for a ConnectFour or TicTacToe game, an error should be displayed', () => {
+ gameAreaController.type = 'ViewingArea'; //Not a game!
+ renderGamesArea();
+
+ expect(screen.queryByTestId(CONNECT_FOUR_AREA_TEST_ID)).toBeNull();
+ expect(screen.queryByTestId(TIC_TAC_TOE_AREA_TEST_ID)).toBeNull();
+
+ expect(screen.getByText(INVALID_GAME_AREA_TYPE_MESSAGE)).toBeInTheDocument();
+ });
+ });
+ describe('[T2.2] Leaderboard', () => {
+ it('Renders the leaderboard with the history when the component is mounted', () => {
+ gameAreaController.mockHistory = [
+ {
+ gameID: nanoid(),
+ scores: {
+ [nanoid()]: 1,
+ [nanoid()]: 0,
+ },
+ },
+ ];
+ renderGamesArea();
+ expect(leaderboardComponentSpy).toHaveBeenCalledWith(
+ {
+ results: gameAreaController.mockHistory,
+ },
+ {},
+ );
+ });
+ it('Renders the leaderboard with the history when the game is updated', () => {
+ gameAreaController.mockHistory = [
+ {
+ gameID: nanoid(),
+ scores: {
+ [nanoid()]: 1,
+ [nanoid()]: 0,
+ },
+ },
+ ];
+ renderGamesArea();
+ expect(leaderboardComponentSpy).toHaveBeenCalledWith(
+ {
+ results: gameAreaController.mockHistory,
+ },
+ {},
+ );
+
+ gameAreaController.mockHistory = [
+ {
+ gameID: nanoid(),
+ scores: {
+ [nanoid()]: 1,
+ [nanoid()]: 1,
+ },
+ },
+ ];
+ act(() => {
+ gameAreaController.emit('gameUpdated');
+ });
+ expect(leaderboardComponentSpy).toHaveBeenCalledWith(
+ {
+ results: gameAreaController.mockHistory,
+ },
+ {},
+ );
+ });
+ });
+ describe('[T2.3] List of observers', () => {
+ beforeEach(() => {
+ gameAreaController.mockObservers = [
+ new PlayerController('player 1', 'player 1', randomLocation()),
+ new PlayerController('player 2', 'player 2', randomLocation()),
+ new PlayerController('player 3', 'player 3', randomLocation()),
+ ];
+ });
+ it('Displays the correct observers when the component is mounted', () => {
+ renderGamesArea();
+ const observerList = screen.getByLabelText('list of observers in the game');
+ const observerItems = observerList.querySelectorAll('li');
+ expect(observerItems).toHaveLength(gameAreaController.mockObservers.length);
+ for (let i = 0; i < observerItems.length; i++) {
+ expect(observerItems[i]).toHaveTextContent(gameAreaController.mockObservers[i].userName);
+ }
+ });
+ it('Displays the correct observers when the game is updated', () => {
+ renderGamesArea();
+ act(() => {
+ gameAreaController.mockObservers = [
+ new PlayerController('player 1', 'player 1', randomLocation()),
+ new PlayerController('player 2', 'player 2', randomLocation()),
+ new PlayerController('player 3', 'player 3', randomLocation()),
+ new PlayerController('player 4', 'player 4', randomLocation()),
+ ];
+ gameAreaController.emit('gameUpdated');
+ });
+ const observerList = screen.getByLabelText('list of observers in the game');
+ const observerItems = observerList.querySelectorAll('li');
+ expect(observerItems).toHaveLength(gameAreaController.mockObservers.length);
+ for (let i = 0; i < observerItems.length; i++) {
+ expect(observerItems[i]).toHaveTextContent(gameAreaController.mockObservers[i].userName);
+ }
+ });
+ });
+ describe('[T2.1] Listeners', () => {
+ it('Registers exactly one listeners when mounted: for gameUpdated', () => {
+ const addListenerSpy = jest.spyOn(gameAreaController, 'addListener');
+ addListenerSpy.mockClear();
+
+ renderGamesArea();
+ expect(addListenerSpy).toBeCalledTimes(1);
+ expect(addListenerSpy).toHaveBeenCalledWith('gameUpdated', expect.any(Function));
+ });
+ it('Does not register listeners on every render', () => {
+ const removeListenerSpy = jest.spyOn(gameAreaController, 'removeListener');
+ const addListenerSpy = jest.spyOn(gameAreaController, 'addListener');
+ addListenerSpy.mockClear();
+ removeListenerSpy.mockClear();
+ const renderData = renderGamesArea();
+ expect(addListenerSpy).toBeCalledTimes(1);
+ addListenerSpy.mockClear();
+
+ renderData.rerender(
+
+
+
+
+ ,
+ );
+
+ expect(addListenerSpy).not.toBeCalled();
+ expect(removeListenerSpy).not.toBeCalled();
+ });
+ it('Removes the listeners when the component is unmounted', () => {
+ const removeListenerSpy = jest.spyOn(gameAreaController, 'removeListener');
+ const addListenerSpy = jest.spyOn(gameAreaController, 'addListener');
+ addListenerSpy.mockClear();
+ removeListenerSpy.mockClear();
+ const renderData = renderGamesArea();
+ expect(addListenerSpy).toBeCalledTimes(1);
+ const addedListeners = addListenerSpy.mock.calls;
+ const addedGameUpdateListener = addedListeners.find(call => call[0] === 'gameUpdated');
+ expect(addedGameUpdateListener).toBeDefined();
+ renderData.unmount();
+ expect(removeListenerSpy).toBeCalledTimes(1);
+ const removedListeners = removeListenerSpy.mock.calls;
+ const removedGameUpdateListener = removedListeners.find(call => call[0] === 'gameUpdated');
+ expect(removedGameUpdateListener).toEqual(addedGameUpdateListener);
+ });
+ it('Creates new listeners if the gameAreaController changes', () => {
+ const removeListenerSpy = jest.spyOn(gameAreaController, 'removeListener');
+ const addListenerSpy = jest.spyOn(gameAreaController, 'addListener');
+ addListenerSpy.mockClear();
+ removeListenerSpy.mockClear();
+ const renderData = renderGamesArea();
+ expect(addListenerSpy).toBeCalledTimes(1);
+
+ gameAreaController = new MockGameAreaController();
+ const removeListenerSpy2 = jest.spyOn(gameAreaController, 'removeListener');
+ const addListenerSpy2 = jest.spyOn(gameAreaController, 'addListener');
+
+ useInteractableAreaControllerSpy.mockReturnValue(gameAreaController);
+ renderData.rerender(
+
+
+
+
+ ,
+ );
+ expect(removeListenerSpy).toBeCalledTimes(1);
+
+ expect(addListenerSpy2).toBeCalledTimes(1);
+ expect(removeListenerSpy2).not.toBeCalled();
+ });
+ });
+ describe('[T2.5] Chat', () => {
+ it('Renders a ChatChannel with the interactableID', () => {
+ renderGamesArea();
+ expect(chatChannelSpy).toHaveBeenCalledWith(
+ {
+ interactableID: gameAreaController.id,
+ },
+ {},
+ );
+ });
+ it('Re-renders the ChatChannel when the interactableID changes', () => {
+ const renderData = renderGamesArea();
+ expect(chatChannelSpy).toHaveBeenCalledWith(
+ {
+ interactableID: gameAreaController.id,
+ },
+ {},
+ );
+ setGameAreaControllerID(nanoid());
+ renderData.rerender(
+
+
+
+
+ ,
+ );
+ expect(chatChannelSpy).toHaveBeenCalledWith(
+ {
+ interactableID: gameAreaController.id,
+ },
+ {},
+ );
+ });
+ });
+});
diff --git a/Assignments/ip2/ip2-handout.zip b/Assignments/ip2/ip2-handout.zip
new file mode 100644
index 00000000..55de3324
Binary files /dev/null and b/Assignments/ip2/ip2-handout.zip differ
diff --git a/Examples/conversation-areas-poster.pdf b/Examples/conversation-areas-poster.pdf
new file mode 100644
index 00000000..812dbdc3
Binary files /dev/null and b/Examples/conversation-areas-poster.pdf differ
diff --git a/Examples/fall-2023-react-examples.zip b/Examples/fall-2023-react-examples.zip
new file mode 100644
index 00000000..24aac47b
Binary files /dev/null and b/Examples/fall-2023-react-examples.zip differ
diff --git a/Examples/git-placeholder.txt b/Examples/git-placeholder.txt
new file mode 100644
index 00000000..2d6401c9
--- /dev/null
+++ b/Examples/git-placeholder.txt
@@ -0,0 +1 @@
+Placeholder file to force git to create a folder here.
\ No newline at end of file
diff --git a/Examples/module-05-design-patterns-examples.zip b/Examples/module-05-design-patterns-examples.zip
new file mode 100644
index 00000000..9f95b446
Binary files /dev/null and b/Examples/module-05-design-patterns-examples.zip differ
diff --git a/Examples/module-06-async-examples.zip b/Examples/module-06-async-examples.zip
new file mode 100644
index 00000000..d0428d01
Binary files /dev/null and b/Examples/module-06-async-examples.zip differ
diff --git a/Examples/module-08-react-examples.zip b/Examples/module-08-react-examples.zip
new file mode 100644
index 00000000..f6012149
Binary files /dev/null and b/Examples/module-08-react-examples.zip differ
diff --git a/Examples/module-09-react-hooks-examples.zip b/Examples/module-09-react-hooks-examples.zip
new file mode 100644
index 00000000..d3f843d1
Binary files /dev/null and b/Examples/module-09-react-hooks-examples.zip differ
diff --git a/Examples/module-12-testing-examples (Mitch's version).zip b/Examples/module-12-testing-examples (Mitch's version).zip
new file mode 100644
index 00000000..790ba87f
Binary files /dev/null and b/Examples/module-12-testing-examples (Mitch's version).zip differ
diff --git a/Examples/module-12-testing-examples.zip b/Examples/module-12-testing-examples.zip
new file mode 100644
index 00000000..790ba87f
Binary files /dev/null and b/Examples/module-12-testing-examples.zip differ
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..620a3690
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2 @@
+index.html:
+ bundle exec jekyll serve
diff --git a/Slides/Module 01.1 Course Introduction.pdf b/Slides/Module 01.1 Course Introduction.pdf
new file mode 100644
index 00000000..b9f8a961
Binary files /dev/null and b/Slides/Module 01.1 Course Introduction.pdf differ
diff --git a/Slides/Module 01.1 Course Introduction.pptx b/Slides/Module 01.1 Course Introduction.pptx
new file mode 100644
index 00000000..1abdc642
Binary files /dev/null and b/Slides/Module 01.1 Course Introduction.pptx differ
diff --git a/Slides/Module 01.2 Requirements Gathering.pdf b/Slides/Module 01.2 Requirements Gathering.pdf
new file mode 100644
index 00000000..cc7dfd0c
Binary files /dev/null and b/Slides/Module 01.2 Requirements Gathering.pdf differ
diff --git a/Slides/Module 01.2 Requirements Gathering.pptx b/Slides/Module 01.2 Requirements Gathering.pptx
new file mode 100644
index 00000000..809f3398
Binary files /dev/null and b/Slides/Module 01.2 Requirements Gathering.pptx differ
diff --git a/Slides/Module 02 From Requirements to Code.pdf b/Slides/Module 02 From Requirements to Code.pdf
new file mode 100644
index 00000000..8b6ab515
Binary files /dev/null and b/Slides/Module 02 From Requirements to Code.pdf differ
diff --git a/Slides/Module 02 From Requirements to Code.pptx b/Slides/Module 02 From Requirements to Code.pptx
new file mode 100644
index 00000000..5eaa26b0
Binary files /dev/null and b/Slides/Module 02 From Requirements to Code.pptx differ
diff --git a/Slides/Module 03 Test Adequacy.pdf b/Slides/Module 03 Test Adequacy.pdf
new file mode 100644
index 00000000..2c8ea966
Binary files /dev/null and b/Slides/Module 03 Test Adequacy.pdf differ
diff --git a/Slides/Module 03 Test Adequacy.pptx b/Slides/Module 03 Test Adequacy.pptx
new file mode 100644
index 00000000..b4fb277b
Binary files /dev/null and b/Slides/Module 03 Test Adequacy.pptx differ
diff --git a/Slides/Module 04 Code Level Design.pdf b/Slides/Module 04 Code Level Design.pdf
new file mode 100644
index 00000000..6337acd6
Binary files /dev/null and b/Slides/Module 04 Code Level Design.pdf differ
diff --git a/Slides/Module 04 Code Level Design.pptx b/Slides/Module 04 Code Level Design.pptx
new file mode 100644
index 00000000..ac727392
Binary files /dev/null and b/Slides/Module 04 Code Level Design.pptx differ
diff --git a/Slides/Module 05 Interaction-Level Design Patterns.pdf b/Slides/Module 05 Interaction-Level Design Patterns.pdf
new file mode 100644
index 00000000..ec8020b8
Binary files /dev/null and b/Slides/Module 05 Interaction-Level Design Patterns.pdf differ
diff --git a/Slides/Module 05 Interaction-Level Design Patterns.pptx b/Slides/Module 05 Interaction-Level Design Patterns.pptx
new file mode 100644
index 00000000..54951908
Binary files /dev/null and b/Slides/Module 05 Interaction-Level Design Patterns.pptx differ
diff --git a/Slides/Module 06 Concurrency Patterns in Typescript.pdf b/Slides/Module 06 Concurrency Patterns in Typescript.pdf
new file mode 100644
index 00000000..92c15366
Binary files /dev/null and b/Slides/Module 06 Concurrency Patterns in Typescript.pdf differ
diff --git a/Slides/Module 06 Concurrency Patterns in Typescript.pptx b/Slides/Module 06 Concurrency Patterns in Typescript.pptx
new file mode 100644
index 00000000..2bf3d7aa
Binary files /dev/null and b/Slides/Module 06 Concurrency Patterns in Typescript.pptx differ
diff --git a/Slides/Module 07.1 Software Process.pdf b/Slides/Module 07.1 Software Process.pdf
new file mode 100644
index 00000000..2807c7cf
Binary files /dev/null and b/Slides/Module 07.1 Software Process.pdf differ
diff --git a/Slides/Module 07.1 Software Process.pptx b/Slides/Module 07.1 Software Process.pptx
new file mode 100644
index 00000000..7bb60002
Binary files /dev/null and b/Slides/Module 07.1 Software Process.pptx differ
diff --git a/Slides/Module 07.2 Agile Planning and Estimation.pdf b/Slides/Module 07.2 Agile Planning and Estimation.pdf
new file mode 100644
index 00000000..63d38181
Binary files /dev/null and b/Slides/Module 07.2 Agile Planning and Estimation.pdf differ
diff --git a/Slides/Module 07.2 Agile Planning and Estimation.pptx b/Slides/Module 07.2 Agile Planning and Estimation.pptx
new file mode 100644
index 00000000..7554c5bb
Binary files /dev/null and b/Slides/Module 07.2 Agile Planning and Estimation.pptx differ
diff --git a/Slides/Module 07.3 Teams.pdf b/Slides/Module 07.3 Teams.pdf
new file mode 100644
index 00000000..b693dfa5
Binary files /dev/null and b/Slides/Module 07.3 Teams.pdf differ
diff --git a/Slides/Module 07.3 Teams.pptx b/Slides/Module 07.3 Teams.pptx
new file mode 100644
index 00000000..d540a832
Binary files /dev/null and b/Slides/Module 07.3 Teams.pptx differ
diff --git a/Slides/Module 08 React Basics.pdf b/Slides/Module 08 React Basics.pdf
new file mode 100644
index 00000000..d4f11fb2
Binary files /dev/null and b/Slides/Module 08 React Basics.pdf differ
diff --git a/Slides/Module 08 React Basics.pptx b/Slides/Module 08 React Basics.pptx
new file mode 100644
index 00000000..7ad2c0c7
Binary files /dev/null and b/Slides/Module 08 React Basics.pptx differ
diff --git a/Slides/Module 09 React Hooks.pdf b/Slides/Module 09 React Hooks.pdf
new file mode 100644
index 00000000..54c1d789
Binary files /dev/null and b/Slides/Module 09 React Hooks.pdf differ
diff --git a/Slides/Module 09 React Hooks.pptx b/Slides/Module 09 React Hooks.pptx
new file mode 100644
index 00000000..24988dc1
Binary files /dev/null and b/Slides/Module 09 React Hooks.pptx differ
diff --git a/Slides/Module 10.1 Distributed Systems Goals and Challenges.pdf b/Slides/Module 10.1 Distributed Systems Goals and Challenges.pdf
new file mode 100644
index 00000000..fdd00b02
Binary files /dev/null and b/Slides/Module 10.1 Distributed Systems Goals and Challenges.pdf differ
diff --git a/Slides/Module 10.1 Distributed Systems Goals and Challenges.pptx b/Slides/Module 10.1 Distributed Systems Goals and Challenges.pptx
new file mode 100644
index 00000000..1e497aa5
Binary files /dev/null and b/Slides/Module 10.1 Distributed Systems Goals and Challenges.pptx differ
diff --git a/Slides/Module 10.2 Distributing Data.pdf b/Slides/Module 10.2 Distributing Data.pdf
new file mode 100644
index 00000000..5b2bcff9
Binary files /dev/null and b/Slides/Module 10.2 Distributing Data.pdf differ
diff --git a/Slides/Module 10.2 Distributing Data.pptx b/Slides/Module 10.2 Distributing Data.pptx
new file mode 100644
index 00000000..8527cee4
Binary files /dev/null and b/Slides/Module 10.2 Distributing Data.pptx differ
diff --git a/Slides/Module 11.1 Distributing Processing (Spring 24; Mitch's Version).pdf b/Slides/Module 11.1 Distributing Processing (Spring 24; Mitch's Version).pdf
new file mode 100644
index 00000000..2dab22ef
Binary files /dev/null and b/Slides/Module 11.1 Distributing Processing (Spring 24; Mitch's Version).pdf differ
diff --git a/Slides/Module 11.1 Distributing Processing (Spring 24; Mitch's Version).pptx b/Slides/Module 11.1 Distributing Processing (Spring 24; Mitch's Version).pptx
new file mode 100644
index 00000000..fe7f830b
Binary files /dev/null and b/Slides/Module 11.1 Distributing Processing (Spring 24; Mitch's Version).pptx differ
diff --git a/Slides/Module 11.1 Distributing Processing.pdf b/Slides/Module 11.1 Distributing Processing.pdf
new file mode 100644
index 00000000..40238508
Binary files /dev/null and b/Slides/Module 11.1 Distributing Processing.pdf differ
diff --git a/Slides/Module 11.1 Distributing Processing.pptx b/Slides/Module 11.1 Distributing Processing.pptx
new file mode 100644
index 00000000..fe7f830b
Binary files /dev/null and b/Slides/Module 11.1 Distributing Processing.pptx differ
diff --git a/Slides/Module 11.2 Case Studies.pdf b/Slides/Module 11.2 Case Studies.pdf
new file mode 100644
index 00000000..29d626d4
Binary files /dev/null and b/Slides/Module 11.2 Case Studies.pdf differ
diff --git a/Slides/Module 11.2 Case Studies.pptx b/Slides/Module 11.2 Case Studies.pptx
new file mode 100644
index 00000000..e29b6ab3
Binary files /dev/null and b/Slides/Module 11.2 Case Studies.pptx differ
diff --git a/Slides/Module 11.3 Communication Patterns.pdf b/Slides/Module 11.3 Communication Patterns.pdf
new file mode 100644
index 00000000..18f2c5fd
Binary files /dev/null and b/Slides/Module 11.3 Communication Patterns.pdf differ
diff --git a/Slides/Module 11.3 Communication Patterns.pptx b/Slides/Module 11.3 Communication Patterns.pptx
new file mode 100644
index 00000000..38ac625b
Binary files /dev/null and b/Slides/Module 11.3 Communication Patterns.pptx differ
diff --git a/Slides/Module 12 Testing Larger Things (Mitch's Version Spring 24).pdf b/Slides/Module 12 Testing Larger Things (Mitch's Version Spring 24).pdf
new file mode 100644
index 00000000..201dfac3
Binary files /dev/null and b/Slides/Module 12 Testing Larger Things (Mitch's Version Spring 24).pdf differ
diff --git a/Slides/Module 12 Testing Larger Things (Mitch's Version Spring 24).pptx b/Slides/Module 12 Testing Larger Things (Mitch's Version Spring 24).pptx
new file mode 100644
index 00000000..47502b36
Binary files /dev/null and b/Slides/Module 12 Testing Larger Things (Mitch's Version Spring 24).pptx differ
diff --git a/Slides/Module 12 Testing Larger Things.pdf b/Slides/Module 12 Testing Larger Things.pdf
new file mode 100644
index 00000000..85b5b138
Binary files /dev/null and b/Slides/Module 12 Testing Larger Things.pdf differ
diff --git a/Slides/Module 12 Testing Larger Things.pptx b/Slides/Module 12 Testing Larger Things.pptx
new file mode 100644
index 00000000..877c471a
Binary files /dev/null and b/Slides/Module 12 Testing Larger Things.pptx differ
diff --git a/Slides/Module 13 Principles and Tech for Cloud.pdf b/Slides/Module 13 Principles and Tech for Cloud.pdf
new file mode 100644
index 00000000..541e30d9
Binary files /dev/null and b/Slides/Module 13 Principles and Tech for Cloud.pdf differ
diff --git a/Slides/Module 13 Principles and Tech for Cloud.pptx b/Slides/Module 13 Principles and Tech for Cloud.pptx
new file mode 100644
index 00000000..fe9281d9
Binary files /dev/null and b/Slides/Module 13 Principles and Tech for Cloud.pptx differ
diff --git a/Slides/Module 14 Continuous Development.pdf b/Slides/Module 14 Continuous Development.pdf
new file mode 100644
index 00000000..e93774c1
Binary files /dev/null and b/Slides/Module 14 Continuous Development.pdf differ
diff --git a/Slides/Module 14 Continuous Development.pptx b/Slides/Module 14 Continuous Development.pptx
new file mode 100644
index 00000000..23b4e845
Binary files /dev/null and b/Slides/Module 14 Continuous Development.pptx differ
diff --git a/Slides/git-placeholder.txt b/Slides/git-placeholder.txt
new file mode 100644
index 00000000..2d6401c9
--- /dev/null
+++ b/Slides/git-placeholder.txt
@@ -0,0 +1 @@
+Placeholder file to force git to create a folder here.
\ No newline at end of file
diff --git a/activities/continuous-development.html b/activities/continuous-development.html
new file mode 100644
index 00000000..17131ea3
--- /dev/null
+++ b/activities/continuous-development.html
@@ -0,0 +1,363 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CI/CD for Covey.Town | CS4530, Spring 2024
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Skip to main content
+
+
+ Link
+
+
+
+
+
+
+ Menu
+
+
+
+
+
+
+ Expand
+
+
+
+
+
+
+
+ (external link)
+
+
+
+
+
+ Document
+
+
+
+
+
+
+ Search
+
+
+
+
+
+
+
+
+
+ Copy
+
+
+
+
+
+
+ Copied
+
+
+
+
+
+
+
+
+
+
+
+
+ Continuous Development Pipelines for Covey.Town
+
+
+
+
+
+
In this activity, you will configure a continuous development pipeline using GitHub Actions, Heroku and Render.com. Our pipeline will use GitHub Actions to build and test your Covey.Town fork, and use Render.com to deploy the application.
+
+
+
+ Pre-requisites
+
+
+
+
+
There are two pre-requisites for this activity:
+
+
Everyone in your team must have a GitHub.com account
+
At least one member of your team must have the GitHub Student Developer Pack - but we would suggest that you all have it, as in addition to providing Heroku credits, this package also provides free access to GitHub CoPilot. Student report success uploading a PDF of their enrollment snapshot/transcript to get the pack - a student ID doesn’t satisfy GitHub’s requirements (there must be a date).
+
+
+
We have carefully crafted this activity around services that provide free trials. One limitation of note is that Heroku’s free trial appears to be a “once per lifetime” offer - if you have used a Heroku free trial in the past few years (since they switched from “free for everyone” to “only free for students”), you won’t be able to claim another free trial. However, only one member of your team needs to set up Heroku - so we hope that at least one of you will be able to use it. If you run into issues surrounding free trials etc., please reach out to the course staff.
+
+
+
+ Creating a GitHub Repository
+
+
+
+
+
Your team’s development must take place within a private GitHub repository in our GitHub Classroom. To create your repository, each member of your team should follow these instructions:
+
+
Sign in to GitHub.com, and then use our invitation to create a repository with the covey.town codebase. You will need to click the “authorize” button next to neu-cs4530 and go through the NEU single sign on. Then you will see a list of groups. Check to see if one of your groupmates has created a group already - if so, select it to join it. Otherwise, create a team with the exact naming scheme “S24 Group XYY”, where X is your section number and YY is your group number. (Updated 2/28 to suggest prefixing with ‘S24’ to avoid collisions with other semesters’ groups).
+
Wait for an email to arrive from GitHub, inviting you to join the repository. This email will be sent to the email address that you used to sign up for GitHub. Click the link to join the repository.
+
The repository should now be created.
+
Clone the repository to your computer. Each of your team members should also follow these steps to join your group and clone the repository to their computer.
+
+
+
This repository will be private, and visible only to your team and the course staff. After the semester ends, you are welcome to make it public - you have complete administrative control of the repository.
+
+
If you run into the error “refusing to allow an OAuth App to create or update workflow” when trying to push to GitHub, the fix is to update your saved authentication credentials for GitHub. For instance, you can follow these instructions to update your credentials in the MacOS Keychain. If all else fails, you can connect to GitHub with SSH instead of HTTPS, which will also solve this problem. This error seems to only occur when pushing a change to the GitHub Actions configuration file, so you could also side-step the problem by having a team mate push this change to GitHub instead (who may not run into this issue).
+
+
+
+ Creating a Twilio account and recording the credentials
+
+
+
+
+
+
You’ll need a Twilio account for your local development environment, and for deployment. You can share a single Twilio account with all of the members in your team (sharing the .env file), but please be careful to avoid posting the contents of your .env file publicly anywhere - someone else might find your credentials and run out all of the free minutes on your account. To set up GitHub Actions and Heroku, we’ll need the values from your .env file - so be sure to get them working before proceeding.
+
+
If you have not configured a Twilio account yet, follow these instructions to set one up. If you have done this before but forgot the API key or secret, you can simply follow the instructions to create a new API key.
+
+
+
Go to Twilio’s website and sign up for an account. You do not need to provide a credit card to create a trial account, but will need to provide a cell phone number.
+ a. When you create your account, to the question to “What do you plan to build…” answer “Other”, to “Which Twilio product are you here to use” answer “Video”, to “How do you want to build with Twilio?” select “With code”, to “Preferred Language” select JavaScript, and to “Would you like Twilio to host your code?” select “No”. (It is OK to select other answers, but selecting these will bring you directly to the “programmable video” part of Twilio’s admin console.
+
Create an API Key: Select the “Account” menu from the top toolbar, and then select “API keys & tokens”. If prompted, re-enter your password.
+
Click “Create API key”, the big blue button at the top right. Enter any descriptive name that you would like for the “friendly name”, and use the other default settings (US region, “standard” key type). Save the “SID” (this will be referenced later as the TWILIO_API_KEY_SID) and the “Secret” (this will be referenced later as the TWILIO_API_KEY_SECRET). Once you are sure that you have copy/pasted these for safe keeping, tick the “Got it!…” checkbox and click “Done”.
+
You should now be back to the “API keys & tokens” page. Take note of the “Live Credentials” in the box lower on this page. The “Account SID” and “Auth token” will be necessary for step 5.
+
Create a .env file in the townService directory, setting the values as follows:
+
+
+
+
+
+
Config Value
+
Description
+
+
+
+
+
TWILIO_ACCOUNT_SID
+
Visible on your twilio account dashboard. Starts with AC…
+
+
+
TWILIO_API_KEY_SID
+
The SID of the new API key you created. Starts with SK…
+
+
+
TWILIO_API_KEY_SECRET
+
The secret for the API key you created.
+
+
+
TWILIO_API_AUTH_TOKEN
+
Visible on your twilio account dashboard.
+
+
+
+
+
You should now be able to start the backend and fronted in your local development environment and have functioning video chat.
+
+
+
+ Set up Heroku for the backend towns service
+
+
+
+
+
We will configure Heroku to automatically deploy the backend townsService to Heroku on every push to the main branch. This way, you can have a publicly available version of your backend service, which will automatically update with any changes that you push to GitHub.
+Please note that there are other PaaS providers that you could use for this step (e.g. Vercel, Render.com, Railway) - but we have found that only Heroku’s free product provides sufficient resources to actually run the backend service.
+
+
+
If you have not already, enroll for the Student Github developer pack and choose “Get student benefits”. Follow the steps as asked after doing this. It generally takes upto 2 business days or more to get the enrollment confirmation from Github.
+
Go to Heroku.com and create an account, or sign in if you already have one using the email id same as the one used for Github account.
+
Enroll in the Heroku for students offer, if you have not already. This would require you to have already enrolled in the Github student developer pack. You will need to complete 3 steps which involves adding a credit card for receiving the platform credits which then can be used for creating apps.
+
After receiving the confirmation of the enrollment in you mail box, the platform credits will be reflected in your billing section in your Heroku account in a few hours. Do not create an app before this.
+
After signing in, create a new app. Choose a name for your app that is somewhat descriptive - it will become part of the URL that you’ll use to access the service. Click “Create app” (no need to go through “Add to pipeline…”).
+
After creating your app on Heroku, open the app’s settings page, revealing a page that looks like this:
+
+
Click “Reveal Config Vars”, and enter the 4 twilio configuration variables from your .env file (the same 4 that you set up on GitHub Actions). Heroku’s “Config Vars” are the way that we tell Heroku what variables to use for .env without having to commit that file into the (publicly viewable) repository. Your configuration settings on Heroku should look like this now:
+
+
Before navigating away from this settings page, scroll down to “Domains”, and take note of the address that Heroku has provided for your app. This should say something like “Your app can be found at https://covey-town-sp24-a800bfec4826.herokuapp.com/”.
+
Click on the “Deploy” tab (in the same ribbon where “Settings” was), and click on “GitHub” next to “Deployment Method” - sign in if necessary
+
Search for your repository in the “Connect to GitHub” section, and click “Connect” next to it. You may need to authorize Heroku to access your GitHub account. Once you have connected your repository, you can click “Enable Automatic Deploys” to have Heroku automatically deploy your app every time you push to GitHub. We suggest ticking the box “Wait for CI to pass before deploy” - this will ensure that your app is only deployed if your tests pass.
+
Lastly, scroll down to the button that says “Deploy Branch” and click it. Watch the logs to see if your deployment is successful. If it is not, you may need to troubleshoot the logs to see what went wrong.
+
To confirm that your service is successfully deployed (after the build log shows that it completed successfully), try to visit it in your browser. Use the URL that you noted in step 8 (“Your app can be found at https://covey-town-sp24-a800bfec4826.herokuapp.com/”). Append towns to the URL, and visit it in your browser (e.g. https://covey-town-sp24-a800bfec4826.herokuapp.com/towns). After a short delay, you should see the response [].
+
+
+
+
+ Set up Render.com for the frontend application
+
+
+
+
+
The last step to our continuous development pipeline will be to automatically deploy our frontend to Render.com. Render.com will create an optimized production build of your frontend (by running npm run build) and host it in their globally-distributed content delivery network.
+
+
+
Go to Render.com and create an account that is linked to the same GitHub account that you used to create your fork of the starter code.
+
After signing in, create a new app by clicking the “new” button. Select “Static Site” as the type of the app.
+
Connect Render.com to your GitHub account, and give it permission to access your repositories.
+
Use the “Connect a repository” picker to select your fork of the starter code. Click next.
+
Configure the site:
+
+
Choose a name for your app - this will become part of the URL that you’ll use to access the application. You can use the default, or change it
+
Leave branch at main, and root directory blank
+
For build command, enter npm install && cd frontend && npm install && npm run prestart && npm run build && npm run export
+
For publish directory, enter frontend/out
+
In “Environment Variables” add a variable with the key NEXT_PUBLIC_TOWNS_SERVICE_URL, setting the value to be the URL of your townService (e.g. https://covey-town-sp24-a800bfec4826.herokuapp.com)
+
Click “Create static site” to create the site.
+
+
+
Render.com will take several minutes to build your site. Once it is deployed, visit the site and confirm that it’s working. If you see an error in the JavaScript log like process is not defined, this indicates that the site was not built with the NEXT_PUBLIC_TOWNS_SERVICE_URL variable set - confirm that it is correctly set, and then rebuild the site on Render.com.
We have posted the instructions for setting up your team repository. You can find them in the start of the CI/CD Pipeline Activity. Please note that setting up the deployment to Heroku requires creating an account and waiting for it to be manually validated by Heroku. We recommend that you start this process as soon as possible to avoid any delays.
+
+
+
+
+
+
+
+
+ Software Development Process
+
+
+
+
+
+
+ Feb 14
+ ·
+
+
+ 1 min read
+
+
+
As part of software development process, each team is expected to use a structured development process, including pull requests, code reviews, etc. Each team will also submit sprint reports, individual surveys, and have weekly meetings with TA Mentor. The development process started last week (as you developed your project plan) and the required “process-related” submissions start this week.
+
+
Here are important submissions to remember for week 6, 8, 10-14:
+
+
Every week all members of a team are expected to meet with their mentor for a regularly scheduled meeting. Weekly Canvas assignments will help track your attendance for these meetings.
+
Every week each student is expected to complete one (Confidential, Peer Evaluation) Survey. The link can be found under the Canvas assignment which will help track if you completed the survey or not.
+
At the end of each sprint, each team will submit a sprint report (and retrospective) through a Canvas assignment.
+
TAs will also review your github commits, PRs, code reviews regularly and will keep an eye on appropriate division of labor within the project team. They will also provide you a weekly assessment of your work.
+
+
+
These assignments count towards “project process” part of the project which is worth 20% of the overall project grade.
+
+
+
+
+
+
+
+
+ Individual Project Deliverable 2 is Now Available + IP1 Regrade Requests + Project Teams Announced
+
+
+
+
+
+
+ Feb 6
+ ·
+
+
+ 1 min read
+
+
+
The second and (final!) individual project deliverable is now released, and will be due on Wednesday, Feb 21 at 11am ET. We strongly encourage you to read through the assignment soon, so that you can begin to formulate a plan of attack to complete this assignment.
Project Team Assignments are now posted on piazza. Please coordinate with your assigned TA Mentors to schedule a kick-off meeting. The first team deliverable will be the preliminary project plan due on Feb 14th
+
+
+
+
+
+
+
+
+
+ Team Formation Survey is Now Available
+
+
+
+
+
+
+ Jan 23
+ ·
+
+
+ 0 min read
+
+
+
Please complete this Team Formation Survey to help us organize you into a team for the term project. EVERY STUDENT must fill this form out by 11am on Wednesday 1/31/2024, or risk being placed in a random team.
+
+
+
+
+
+
+
+
+
+ Welcome to CS4530 - Spring 2024
+
+
+
+
+
+
+ Jan 8
+ ·
+
+
+ 1 min read
+
+
+
On behalf of the entire instructional team (all 3 instructors and 15 TAs), welcome to the Spring 2024 edition of CS 4530! This website will contain all of the lectures, assignments and tutorials for the class. Our Canvas site contains your gradebook as well as single-sign-on links to Piazza (for discussion), instructions for submitting assignments and replicates much of the material from the class website.
+
+
In advance of the first week of class, we’ve shared the calendars for each section, the first two lectures, and tutorials on installing your IDE, Typescript, and unit testing with Jest. The schedule of office hours is also posted and we will start holding office hours from Monday Jan 8th.
+
+
The first individual project deliverable is now available. This deliverable is due by January 24th at 11am ET. Your work will be submitted on Autograder.io which can be accessed through neu.autograder.io. Please note the autograding script will impose a strict rate limit of 5 submissions per 24 hours. This limit exists to encourage you to start early on this assignment. Feel free to use piazza to ask questions and use office hours if you need help. We have 75 hours of scheduled TA office hours per week starting today.
+
+
We are excited to meet you all this week!
+
+
+
+
+
+
+
+
+
+ Initial Website Launched
+
+
+
+
+
+
+ Dec 18
+ ·
+
+
+ 0 min read
+
+
+
Welcome to the course website for CS4530, Spring 2024! Over the coming weeks, we will be populating this website (and Canvas) with more information about the course.