Skip to content

Commit b4650c6

Browse files
committed
add: rough mock koan
1 parent d6683d2 commit b4650c6

4 files changed

Lines changed: 941 additions & 0 deletions

File tree

F25/koans/brain_in_a_jar/mocks.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
2+
/**
3+
* 0320 Koan: "How do you know you're not a brain in a jar?"
4+
*
5+
* This one is messy at the moment, sorry. But ask yourself that
6+
* question. Mocking is all about asking that question for a function,
7+
* class, or method that you write.
8+
*/
9+
10+
11+
export const providence_lat = 41.8240;
12+
export const providence_lon = -71.4128;
13+
14+
interface TemperatureResult {
15+
success: boolean,
16+
degrees?: number,
17+
scale?: 'F' | 'C'
18+
}
19+
20+
/** Make an API call to the National Weather Service. I'm leaving out
21+
* Zod / careful validation here, because that's not the point of this
22+
* example. The point is that this function _calls a real web api_.
23+
*/
24+
async function getRealTemperature(lat: number, lon: number): Promise<TemperatureResult> {
25+
// As a demo, I'm using then/catch here instead of await.
26+
return await fetch(`https://api.weather.gov/points/${lat},${lon}`)
27+
.then(res => {
28+
if (!res.ok) return {success: false}
29+
return res.json();
30+
})
31+
.then(data => {
32+
const forecastUrl = data.properties.forecast;
33+
return fetch(forecastUrl);
34+
})
35+
.then(res => {
36+
if (!res.ok) return {success: false}
37+
return res.json();
38+
})
39+
.then(data => {
40+
const timePeriodsData = data?.properties?.periods;
41+
// This isn't actually right; it'll return the temp
42+
// for the _next time period_, not the current temp.
43+
// See: https://github.com/tnelson/pvd-weather/blob/main/src/App.tsx
44+
//console.log(`${timePeriodsData[0].temperature}`)
45+
return {success: true,
46+
degrees: timePeriodsData[0].temperature,
47+
scale: timePeriodsData[0].temperatureUnit}
48+
})
49+
.catch(err => {
50+
return {success: false}
51+
});
52+
}
53+
54+
/** But what if we want to do something with that temperature? */
55+
async function weatherReportProvidence(source: WeatherSource) {
56+
const report = await source(providence_lat, providence_lon)
57+
console.log(`It's ${report.degrees} ${report.scale} out!`)
58+
}
59+
60+
/** Any function with this shape works as a weather source. */
61+
type WeatherSource = (latarg: number, lonarg: number) => Promise<TemperatureResult>
62+
63+
/** Build a "temperature source" that never actually asks the NWS, and just
64+
* returns the provided constant value. */
65+
function buildTemperatureMock(temp: number, scale: 'F' | 'C'): WeatherSource {
66+
// This builder returns an async function indistinguishable from the real source.
67+
// (Note: we need the explicit return type here to get TypeScript to infer...)
68+
return async function(lat: number, lon: number): Promise<TemperatureResult> {
69+
return {success: true, degrees: temp, scale: scale}
70+
}
71+
}
72+
73+
const alwaysSunny = buildTemperatureMock(72, 'F')
74+
75+
/** Note: don't try this outside of an async function.*/
76+
async function demo() {
77+
// weatherReportProvidence can't tell the difference.
78+
console.log(`real data:`)
79+
await weatherReportProvidence(getRealTemperature)
80+
console.log(`mock data:`)
81+
// for prototyping/testing
82+
await weatherReportProvidence(alwaysSunny)
83+
}
84+
demo()

0 commit comments

Comments
 (0)