Year #3, Week #10 đ» đȘ
New stuff we learned this week:
Dependency Injection
- You can make things that are hard to test easier, by a technique called âDependency Injectionâ. This means that instead of your code reaching out to the outside world directly for itâs dependencies (like database, network APIâs, etc), you explicitly pass IN (or âinjectâ) these dependencies from the outside.
- Passing in (injecting) dependencies from the outside allows you to swap out mock versions for testing, allowing you to easily exercize all of the hard-to-reach edge cases of your app in a fast, reliable way.
Homework Plan (2 weeks)
- 1 day Monkey Assignment #17
- 2 day review all flashcards in your (old) app.
- 2 days touch typing practice
- 1 day King C reading assignment (chapter 10) đ
- 1 day King C exercizes đ
- 1 day Read the Docs! Jest Assignment
- 1 day Flashcards API Jest Assignment đ
- 1 day Flashcards WebApp Jest Assignment đ
- 2 days watch all Dan Abramovâs Redux Videos
- 6 days Execute Program homework
Monkey #17
- Address all feedback from prior MRâs, and merge.
- Create a new branch.
- Double-check that you did the first two steps.
- Triple-check that you did the first three steps.
- Start at section 2.8 - Call Expressions. Work through that section, and commit your work when you finish.
- As always, make sure to try to do as much as you can without the videos, but always also watch the videos and update your code to (mostly) match.
- Video link
- Submit a MR, Review your diffs and fixup!!, then slack the MR url
King C Chapter 10 Project đ
- First, make sure youâve slowly and carefully read all of chapter 10 of King C. assignment.
- Merge your
king-c
repo branch from last week, and CREATE A NEW BRANCH. - NOTE: For the exercizes that build on the code from the chapter, you donât
need to re-type that all in, Iâve got the relavent chunks of code
in this snippet (It has both
poker.c
, and if you scroll down,stack.c
) - Complete the following programming projects from chapter 10, making a new file for every one:
Project #1
Project #2
Project #4
Project #6
Who doesnât love a good reverse polish notation calculator! đ€Project #7
Kiah Credit: âš
Read the Docs! Jest Edition đ
- Read the following sections of the Jest docs site
- Using Matchers
- Testing Async Code
- Setup & Teardown
- Mock Functions (you donât have to understand perfectly all of this, just try to get a high-level sense of whatâs possible with their mocking helpers, sow a few seeds in your brainâŠ)
- Then, skim some of this page, and find one cool thing you didnât know about, and post a description about it in Slack.
Flashcards WebApp Jest Assignment đ
- Make sure youâve completed the âRead the Docs! Jestâ assignment first.
- Make sure youâve addressed any feedback from your last web app MR, and merge, pull, etc.
- Then, make a new branch.
- Did you make a new branch? Do you love making cookies?
- Take a few minutes and read the short
readme.md
for the@friends-library/dev
package. - Install the package.
- Write some tests that cover all of the current things your reducer does. You should create some state, then call your reducer with that state and each of your actions, and then make assertions about the new state. Remember, our reducer actually mutates the state object, so it doesnât return a new state object (that is handled under the hood for you in the reduxlite library).
- Be sure youâve covered any edge cases, like the first and last card, or anything else you can think of.
- clean up your code, make sure youâve removed any debugging things, and submit a MR.
Flashcards API Jest Assignment đ
- Make sure youâve first completed the âWebApp Jestâ assignment before working on this one.
- Make sure youâve addressed any feedback from your last API MR, and merge, pull, etc.
- Then, make a new branch.
- Did you make a new branch? Do you love making cookies?
- Take a minute and add the vscode extension called âInline SQLâ by
jtladieras
. It allows you to get syntax highlighting for sql like so:
const QUERY = /*sql*/ `SELECT * FROM users`;
- Now, weâll start by creating a database abstraction that we can mock in
tests. Create a file called
src/db.ts
. - If you havenât already, lets also create a file dedicated to types for our
API, called
src/types.ts
. In the types file, letâs create an interface for our database abstraction, start it out as an empty interface:
export interface Database {}
- next, in the same file, letâs make a type called
Response
which is a tuple of an HTTP status code and some json (you can useany
for the json, for now at least). Bonus points if you remember how to name your tuple members. - next, letâs make a new file in
src/
calledroute-responders.ts
. The purpose of this file is to export a bunch of functions, one for each route. These are the pure functions weâre extracting out of our messy, dependency-filled world. They each will take an instance of ourDatabase
type, and maybe some other parameters. And they will all return a Promise of ourResponse
tuple type. - create (and export) a route responder called
getCards()
. It should take aDatabase
as an argument, and return a promise of aResponse
. Fill in some dummy code to make it type check for now. (Hint: mark the function asasync
â then you wonât have to muck around with making your own promises). - Ok, now weâll flesh out our DB abstraction a bit. Add a requirement to the
Database
type, that it has a property calledgetAllCards
that returns a promise of aResult
of an array ofCard
s. (Hint: theResult
type can be imported from@htc/simple-sql
. Hint 2: If you havenât already done so, you should have a dedicated type for yourCard
row. Move it intosrc/types.ts
if itâs not already there.) - Next, letâs make our âliveâ database abstraction. Make a file called
src/db.ts
. In it, export a default new class namedLiveDatabase
.- Make sure it
implements Database
(which youâll need to import) - have it take an instance of
SimpleMySQL
in itâs constructor. Make it aprivate
property calledmysql
. - fill in the required
getAllCards()
function using thethis.mysql
property, making a real query to the database, and returning the result. Use the/* sql */
comment trick to get syntax highlighting for your SQL (via the new extension).
- Make sure it
- Below the
LiveDatabase
, letâs make and export another class, calledMockDatabase
â it should also implement theDatabase
interface. Fill in the required function with anything that makes the type-checker happy. - OK, itâs time to write some tests. Install the
@friends-library/dev
library, and set up two scripts for testing, one fornpm run test
and one fornpm run test:watch
. - Create a
src/__tests__/route-responders.spec.ts
file. In it, write a couple tests for thegetCards()
function exported fromsrc/route-responders.ts
. Pass the function an instance ofMockDatabase
. In order to control what our mock returns, you can replace the function you care about in your test, like this:
const mockDb = new MockDatabase();
mockDb.getAllCards = () => Promise.resolve({ ok: false, error: `oh noes!` });
- write tests for the error scenario, and the success scenario. Make sure you
are asserting on what the status code is, and what the json is. To get
these to pass, youâll need to actually fill in a real implementation of the
getCards()
function insrc/route-responders.ts
, using the injected database dependency. - Next, go into your
src/index.ts
file, and use all your shiny new code instead of the inlined function that is there for your/cards
route:- create an instance of your âliveâ database, by passing it a fully configured
SimpleMySQL
object - pull the innards out of your
app.get("/cards")
route, and have it call thegetCards()
function fromsrc/route-responders
. - use the result you get back from the route responder to set the status code and send back json.
- HINT: make the express function wrapping your route responder
async
so you can useawait
in it and not muck around with promises directly. - HINT: instead of doing
import { getCards } from './route-responders';
you can doimport * as routes from './route-responders';
Then, you can callroutes.getCards()
, which reads kind of nice, and you wonât end up having to import a billion responders as your app grows.
- create an instance of your âliveâ database, by passing it a fully configured
- Test that the app still works when wired together using the
api.http
file you created a few weeks ago. - Finally, a bit of cleanup:
- move the
MockDatabase()
class fromsrc/db.ts
intosrc/__tests__/mock-db.ts
- your tests probably create a new MockDatabase for each test. This is not a big deal now, since we only have a few tests, but eventually this will get pretty repetative. Whatâs something you read about in the jest docs that could clean this up? Figure that out and implement it.
- review all your code for stray comments,
console.log
s, etc.
- move the
- Push up a MR, review your diffs, and clean up anything you notice. Then slack me the MR URL.
Redux Dan Abramov Homework
- Watch all of the videos (total 2 hours, 1 min) of the Fundamentals of Redux Course from Dan Abramov Egghead course. You might need to sign up for a free account. I already unblocked it on Gertrude, but havenât tested if I need anything else unblocked to make it work.
- The video is broken into lots of small chunks, so you can slowly pick your way through them over the next two weeks.