Skip to content

Instantly share code, notes, and snippets.

@alexFaunt
Last active April 19, 2021 14:10
Show Gist options
  • Save alexFaunt/512010851d992c00caba055e951f3272 to your computer and use it in GitHub Desktop.
Save alexFaunt/512010851d992c00caba055e951f3272 to your computer and use it in GitHub Desktop.
Diff
diff --git a/README.md b/README.md
index 2b34e2a..2a0b245 100644
--- a/README.md
+++ b/README.md
@@ -3,14 +3,13 @@
## Setup
```
-yarn && (cd client && yarn)
+yarn
```
-
## Running
```
-yarn dev
+yarn server
```
## Tests
@@ -22,27 +21,15 @@ yarn test
## Background
At Fiit we collect stats for user workouts, we then present these stats to our users in meaningful ways.
-The aim of this task is to present a styled list of workouts with associated stats.
+The aim of this task is to fetch data stored for workouts and do some aggregate calculations on it.
## Tasks
-### Full stack
-
-1. Make the `workouts.js` api return results from the workout.json file
-2. Display drop down list of workouts returned in the UI instead of always first workout
-3. Hook up stats api with workoutId to fetch stats for the workout
-4. Implement stats api to calculate average heart rate and total reps from the json data
-5. If the stats fail to load in under 2 seconds, return an error instead (workout #5 looks particularly slow)
-6. Style the results page to make it look nicer
-
-### Frontend
-
-1. Display drop down list of workouts returned in the UI instead of always first workout
-2. Add and extend the existing Stats component to the page. When a workout is selected from the drop down list: load the stats for that workout and display them. Some hard coded stats are returned from GraphQL which will suffice for this step.
-3. Show the image for the selected workout so that it is centered in a square on all screen sizes - design.png
-4. Hook up the rest of the workouts and randomise the stats in GraphQL - if comfortable attempt to load the json data from the files.
-5. On changing the selected workout, add some kind of animation or fade transition between the old details and new ones
-6. Talk through breaking up the files / managing this state appropriately in production
+1. Complete the function `loadStatsFilesById` in `server/src/api/data/utils/load-stats-files.js` (ignore the delay part). You'll probably want to write a unit test to make sure it works
+2. Using this function, update `getStats` in `server/src/api/stats.js` to calculate and return the total reps and then the average heart rate for a given workout. Tests already exist for this
+3. If the stats fail to load in under 2 seconds, return an error instead - comment back in `delayedLoadStatsFilesById` in `load-stats-files` to make workout 5 load slowly
+4. Extend the tests for task number 3
+5. GraphQL extension - add stats to the type Workout and resolve it using `getStats` - playground can be used to test
## Followup questions
diff --git a/package.json b/package.json
index f04c29a..0b90813 100644
--- a/package.json
+++ b/package.json
@@ -4,8 +4,7 @@
"scripts": {
"client": "cd client && yarn start",
"server": "nodemon --ignore ./client server/src/server.js",
- "dev": "REACT_APP_SERVER_PORT=$(./scripts/get-available-port.sh) concurrently --kill-others-on-fail \"yarn server\" \"yarn client\"",
- "test": "jest server/ && (cd client && yarn test)"
+ "test": "jest"
},
"dependencies": {
"apollo-server-express": "^2.11.0",
diff --git a/server/src/api/data/utils/delay.js b/server/src/api/data/utils/delay.js
new file mode 100644
index 0000000..254565d
--- /dev/null
+++ b/server/src/api/data/utils/delay.js
@@ -0,0 +1,3 @@
+const delay = (time) => new Promise((resolve) => setTimeout(resolve, time));
+
+module.exports = delay;
diff --git a/server/src/api/data/utils/load-stats-files.js b/server/src/api/data/utils/load-stats-files.js
index f77c169..0c64698 100644
--- a/server/src/api/data/utils/load-stats-files.js
+++ b/server/src/api/data/utils/load-stats-files.js
@@ -1,26 +1,23 @@
-const fs = require('fs');
-const path = require('path');
-const { promisify } = require('util');
+const delay = require('./delay');
-const readDir = promisify(fs.readdir);
-const readFile = promisify(fs.readFile);
+async function loadStatsFilesById(id) {
+ // Given workout id number 1, load the appropriate stats files
+ return statsFiles;
+};
+
+module.exports = loadStatsFilesById
-const delay = (time) => new Promise((resolve) => setTimeout(resolve, time));
-async function loadStatsFilesById(id) {
- const folder = path.resolve(__dirname, `../stats/workout${id}`);
- const fileNames = await readDir(folder);
- const fileReads = fileNames.map((fileName) => readFile(path.join(folder, fileName), 'utf-8'));
- const statsFiles = await Promise.all(fileReads);
- // simulate bad network
+
+// For a later task we'll simulate a network delay on workout number 5 - ignore for now!
+async function delayedLoadStatsFilesById(id) {
if (id === 5) {
await delay(5000);
}
+ return loadStatsFilesById(id);
+}
- return statsFiles;
-};
-
-module.exports = loadStatsFilesById
+// module.exports = delayedLoadStatsFilesById
diff --git a/server/src/api/data/utils/load-stats-files.test.js b/server/src/api/data/utils/load-stats-files.test.js
new file mode 100644
index 0000000..341ea2a
--- /dev/null
+++ b/server/src/api/data/utils/load-stats-files.test.js
@@ -0,0 +1,12 @@
+const loadStatsFilesById = require('./load-stats-files');
+
+
+it('It loads the stats files by workout id', async () => {
+ const results = await loadStatsFilesById(1);
+
+ // The first workout has 158 chunks
+
+ // And at the start of the 30th chunk my heart rate was 156
+
+ expect(results).toBe('hmmmm? what could i check?')
+});
diff --git a/server/src/api/stats.js b/server/src/api/stats.js
index 5236ab4..4528f2d 100644
--- a/server/src/api/stats.js
+++ b/server/src/api/stats.js
@@ -1,12 +1,12 @@
const loadStatsFilesById = require('./data/utils/load-stats-files');
-async function getStats() {
+async function getStats(workoutId) {
return {
- bpm: {
- average: 113,
- },
reps: {
- sum: 225
+ sum: 222,
+ },
+ bpm: {
+ average: 141,
},
};
}
diff --git a/server/src/api/stats.test.js b/server/src/api/stats.test.js
index 3fafe41..1ee1457 100644
--- a/server/src/api/stats.test.js
+++ b/server/src/api/stats.test.js
@@ -1,11 +1,45 @@
const stats = require('./stats');
-it('I can fetch stats of workout 1', async () => {
- const results = await stats(1);
+it('returns the sum of reps for each workout', async () => {
+ const results1 = await stats(1);
+ expect(results1.reps.sum).toBe(0);
- expect(results).toMatchObject({
- averageHeartRate: '113',
- totalReps: '255'
- });
+ const results2 = await stats(2);
+ expect(results2.reps.sum).toBe(222);
+ const results3 = await stats(3);
+ expect(results3.reps.sum).toBe(0);
+
+ const results4 = await stats(4);
+ expect(results4.reps.sum).toBe(169);
+});
+
+// Depending on the calculation method you can get different results, we're not too fussed what method is used
+it('returns the average bpm for each workout', async () => {
+ const results1 = await stats(1);
+ expect(results1.bpm.average).toBe(139);
+
+ const results2 = await stats(2);
+ expect(results2.bpm.average).toBe(141);
+
+ const results3 = await stats(3);
+ expect(results3.bpm.average).toBe(135);
+
+ const results4 = await stats(4);
+ expect(results4.bpm.average).toBe(136);
+});
+
+// Depending on the calculation method you can get different results, we're not too fussed what method is used
+it.skip('returns the average bpm for each workout', async () => {
+ const results1 = await stats(1);
+ expect(results1.bpm.average).toBe(137);
+
+ const results2 = await stats(2);
+ expect(results2.bpm.average).toBe(140);
+
+ const results3 = await stats(3);
+ expect(results3.bpm.average).toBe(134);
+
+ const results4 = await stats(4);
+ expect(results4.bpm.average).toBe(135);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment