@jeremyckahn/farmhand 1.22.0 → 1.22.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.html CHANGED
@@ -75,7 +75,7 @@
75
75
  gtag('config', analyticsID)
76
76
  })()
77
77
  </script>
78
- <script type="module" crossorigin src="./assets/index-DgErVmlw.js"></script>
78
+ <script type="module" crossorigin src="./assets/index-C_BBT4NW.js"></script>
79
79
  <link rel="stylesheet" crossorigin href="./assets/index-CNcrTYN-.css">
80
80
  <link rel="manifest" href="./manifest.webmanifest"></head>
81
81
  <body>
@@ -1,3 +1,3 @@
1
- if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,o)=>{const r=e||("document"in self?document.currentScript.src:"")||location.href;if(s[r])return;let d={};const l=e=>i(e,r),t={module:{uri:r},exports:d,require:l};s[r]=Promise.all(n.map(e=>t[e]||l(e))).then(e=>(o(...e),d))}}define(["./workbox-2fbc6a65"],function(e){"use strict";self.addEventListener("message",e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()}),e.precacheAndRoute([{url:"index.html",revision:"bcc81d18b2d0f7e0cbaf0b44607d79d8"},{url:"electron.js",revision:"b0456826f47539f6c1957c3add5eb959"},{url:"assets/workbox-window.prod.es5-Bd17z0YL.js",revision:null},{url:"assets/index-DgErVmlw.js",revision:null},{url:"assets/index-CNcrTYN-.css",revision:null},{url:"favicon.ico",revision:"445bb19d4a8fd46eb433dd43cbdce691"},{url:"logo192.png",revision:"70746d790b8990639d1390337d77d81a"},{url:"logo512.png",revision:"b044ab46b3f33f0e2d313d961bf1f654"},{url:"logoMaskable.png",revision:"23be58ccf16df9f43658aad3da30056d"},{url:"manifest.webmanifest",revision:"3ad071a00582451c9cdeb827b37b9ebe"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});
1
+ if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,o)=>{const r=e||("document"in self?document.currentScript.src:"")||location.href;if(s[r])return;let d={};const l=e=>i(e,r),t={module:{uri:r},exports:d,require:l};s[r]=Promise.all(n.map(e=>t[e]||l(e))).then(e=>(o(...e),d))}}define(["./workbox-2fbc6a65"],function(e){"use strict";self.addEventListener("message",e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()}),e.precacheAndRoute([{url:"index.html",revision:"b549ee2133c12f6a96628689440ee32d"},{url:"electron.js",revision:"b0456826f47539f6c1957c3add5eb959"},{url:"assets/workbox-window.prod.es5-Bd17z0YL.js",revision:null},{url:"assets/index-C_BBT4NW.js",revision:null},{url:"assets/index-CNcrTYN-.css",revision:null},{url:"favicon.ico",revision:"445bb19d4a8fd46eb433dd43cbdce691"},{url:"logo192.png",revision:"70746d790b8990639d1390337d77d81a"},{url:"logo512.png",revision:"b044ab46b3f33f0e2d313d961bf1f654"},{url:"logoMaskable.png",revision:"23be58ccf16df9f43658aad3da30056d"},{url:"manifest.webmanifest",revision:"3ad071a00582451c9cdeb827b37b9ebe"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});
2
2
  //# sourceMappingURL=service-worker.js.map
3
3
  //# sourceMappingURL=service-worker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"service-worker.js","sources":["../../../../../tmp/4a09879dcd62dc4f812bd7d7258abc68/service-worker.js"],"sourcesContent":["import {precacheAndRoute as workbox_precaching_precacheAndRoute} from '/home/runner/work/farmhand/farmhand/node_modules/workbox-precaching/precacheAndRoute.mjs';\nimport {cleanupOutdatedCaches as workbox_precaching_cleanupOutdatedCaches} from '/home/runner/work/farmhand/farmhand/node_modules/workbox-precaching/cleanupOutdatedCaches.mjs';\nimport {registerRoute as workbox_routing_registerRoute} from '/home/runner/work/farmhand/farmhand/node_modules/workbox-routing/registerRoute.mjs';\nimport {NavigationRoute as workbox_routing_NavigationRoute} from '/home/runner/work/farmhand/farmhand/node_modules/workbox-routing/NavigationRoute.mjs';\nimport {createHandlerBoundToURL as workbox_precaching_createHandlerBoundToURL} from '/home/runner/work/farmhand/farmhand/node_modules/workbox-precaching/createHandlerBoundToURL.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\nself.addEventListener('message', (event) => {\n if (event.data && event.data.type === 'SKIP_WAITING') {\n self.skipWaiting();\n }\n});\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"index.html\",\n \"revision\": \"bcc81d18b2d0f7e0cbaf0b44607d79d8\"\n },\n {\n \"url\": \"electron.js\",\n \"revision\": \"b0456826f47539f6c1957c3add5eb959\"\n },\n {\n \"url\": \"assets/workbox-window.prod.es5-Bd17z0YL.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/index-DgErVmlw.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/index-CNcrTYN-.css\",\n \"revision\": null\n },\n {\n \"url\": \"favicon.ico\",\n \"revision\": \"445bb19d4a8fd46eb433dd43cbdce691\"\n },\n {\n \"url\": \"logo192.png\",\n \"revision\": \"70746d790b8990639d1390337d77d81a\"\n },\n {\n \"url\": \"logo512.png\",\n \"revision\": \"b044ab46b3f33f0e2d313d961bf1f654\"\n },\n {\n \"url\": \"logoMaskable.png\",\n \"revision\": \"23be58ccf16df9f43658aad3da30056d\"\n },\n {\n \"url\": \"manifest.webmanifest\",\n \"revision\": \"3ad071a00582451c9cdeb827b37b9ebe\"\n }\n], {});\nworkbox_precaching_cleanupOutdatedCaches();workbox_routing_registerRoute(new workbox_routing_NavigationRoute(workbox_precaching_createHandlerBoundToURL(\"index.html\")));\n\n\n"],"names":["self","addEventListener","event","data","type","skipWaiting","workbox_precaching_precacheAndRoute","url","revision","workbox_precaching_cleanupOutdatedCaches","workbox_routing_registerRoute","workbox_routing_NavigationRoute","workbox_precaching_createHandlerBoundToURL"],"mappings":"inBAmBAA,KAAKC,iBAAiB,UAAYC,IAC5BA,EAAMC,MAA4B,iBAApBD,EAAMC,KAAKC,MAC3BJ,KAAKK,gBASTC,EAAAA,iBAAoC,CAClC,CACEC,IAAO,aACPC,SAAY,oCAEd,CACED,IAAO,cACPC,SAAY,oCAEd,CACED,IAAO,6CACPC,SAAY,MAEd,CACED,IAAO,2BACPC,SAAY,MAEd,CACED,IAAO,4BACPC,SAAY,MAEd,CACED,IAAO,cACPC,SAAY,oCAEd,CACED,IAAO,cACPC,SAAY,oCAEd,CACED,IAAO,cACPC,SAAY,oCAEd,CACED,IAAO,mBACPC,SAAY,oCAEd,CACED,IAAO,uBACPC,SAAY,qCAEb,CAAA,GACHC,EAAAA,wBAA2CC,EAAAA,cAA8B,IAAIC,EAAAA,gBAAgCC,0BAA2C"}
1
+ {"version":3,"file":"service-worker.js","sources":["../../../../../tmp/44ebbc81530230699b16f7f886c50e94/service-worker.js"],"sourcesContent":["import {precacheAndRoute as workbox_precaching_precacheAndRoute} from '/home/runner/work/farmhand/farmhand/node_modules/workbox-precaching/precacheAndRoute.mjs';\nimport {cleanupOutdatedCaches as workbox_precaching_cleanupOutdatedCaches} from '/home/runner/work/farmhand/farmhand/node_modules/workbox-precaching/cleanupOutdatedCaches.mjs';\nimport {registerRoute as workbox_routing_registerRoute} from '/home/runner/work/farmhand/farmhand/node_modules/workbox-routing/registerRoute.mjs';\nimport {NavigationRoute as workbox_routing_NavigationRoute} from '/home/runner/work/farmhand/farmhand/node_modules/workbox-routing/NavigationRoute.mjs';\nimport {createHandlerBoundToURL as workbox_precaching_createHandlerBoundToURL} from '/home/runner/work/farmhand/farmhand/node_modules/workbox-precaching/createHandlerBoundToURL.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\nself.addEventListener('message', (event) => {\n if (event.data && event.data.type === 'SKIP_WAITING') {\n self.skipWaiting();\n }\n});\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"index.html\",\n \"revision\": \"b549ee2133c12f6a96628689440ee32d\"\n },\n {\n \"url\": \"electron.js\",\n \"revision\": \"b0456826f47539f6c1957c3add5eb959\"\n },\n {\n \"url\": \"assets/workbox-window.prod.es5-Bd17z0YL.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/index-C_BBT4NW.js\",\n \"revision\": null\n },\n {\n \"url\": \"assets/index-CNcrTYN-.css\",\n \"revision\": null\n },\n {\n \"url\": \"favicon.ico\",\n \"revision\": \"445bb19d4a8fd46eb433dd43cbdce691\"\n },\n {\n \"url\": \"logo192.png\",\n \"revision\": \"70746d790b8990639d1390337d77d81a\"\n },\n {\n \"url\": \"logo512.png\",\n \"revision\": \"b044ab46b3f33f0e2d313d961bf1f654\"\n },\n {\n \"url\": \"logoMaskable.png\",\n \"revision\": \"23be58ccf16df9f43658aad3da30056d\"\n },\n {\n \"url\": \"manifest.webmanifest\",\n \"revision\": \"3ad071a00582451c9cdeb827b37b9ebe\"\n }\n], {});\nworkbox_precaching_cleanupOutdatedCaches();workbox_routing_registerRoute(new workbox_routing_NavigationRoute(workbox_precaching_createHandlerBoundToURL(\"index.html\")));\n\n\n"],"names":["self","addEventListener","event","data","type","skipWaiting","workbox_precaching_precacheAndRoute","url","revision","workbox_precaching_cleanupOutdatedCaches","workbox_routing_registerRoute","workbox_routing_NavigationRoute","workbox_precaching_createHandlerBoundToURL"],"mappings":"inBAmBAA,KAAKC,iBAAiB,UAAYC,IAC5BA,EAAMC,MAA4B,iBAApBD,EAAMC,KAAKC,MAC3BJ,KAAKK,gBASTC,EAAAA,iBAAoC,CAClC,CACEC,IAAO,aACPC,SAAY,oCAEd,CACED,IAAO,cACPC,SAAY,oCAEd,CACED,IAAO,6CACPC,SAAY,MAEd,CACED,IAAO,2BACPC,SAAY,MAEd,CACED,IAAO,4BACPC,SAAY,MAEd,CACED,IAAO,cACPC,SAAY,oCAEd,CACED,IAAO,cACPC,SAAY,oCAEd,CACED,IAAO,cACPC,SAAY,oCAEd,CACED,IAAO,mBACPC,SAAY,oCAEd,CACED,IAAO,uBACPC,SAAY,qCAEb,CAAA,GACHC,EAAAA,wBAA2CC,EAAAA,cAA8B,IAAIC,EAAAA,gBAAgCC,0BAA2C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeremyckahn/farmhand",
3
- "version": "1.22.0",
3
+ "version": "1.22.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -7,7 +7,7 @@ import { noop } from '../../utils/noop.js'
7
7
  import { AppBar } from './AppBar.js'
8
8
 
9
9
  const defaultProps = {
10
- dayCount: 0,
10
+ dayCount: 1,
11
11
  handleClickNotificationIndicator: noop,
12
12
  money: 0,
13
13
  showNotifications: false,
@@ -34,19 +34,19 @@ test('displays money amount', () => {
34
34
  })
35
35
 
36
36
  test('displays the current day and season', () => {
37
- render(<AppBar {...defaultProps} dayCount={0} />)
37
+ render(<AppBar {...defaultProps} dayCount={1} />)
38
38
 
39
39
  expect(screen.getByText('Day 1 of Spring')).toBeInTheDocument()
40
40
  })
41
41
 
42
42
  test('displays the correct day and season after the season boundary', () => {
43
- render(<AppBar {...defaultProps} dayCount={15} />)
43
+ render(<AppBar {...defaultProps} dayCount={16} />)
44
44
 
45
45
  expect(screen.getByText('Day 1 of Summer')).toBeInTheDocument()
46
46
  })
47
47
 
48
48
  test('displays the correct day count partway through a season', () => {
49
- render(<AppBar {...defaultProps} dayCount={5} />)
49
+ render(<AppBar {...defaultProps} dayCount={6} />)
50
50
 
51
51
  expect(screen.getByText('Day 6 of Spring')).toBeInTheDocument()
52
52
  })
@@ -15,7 +15,7 @@ vitest.mock('../../data/maps.js')
15
15
  describe('Item', () => {
16
16
  const baseProps = {
17
17
  completedAchievements: {},
18
- dayCount: 0,
18
+ dayCount: 1,
19
19
  historicalValueAdjustments: [],
20
20
  inventory: [],
21
21
  inventoryLimit: INFINITE_STORAGE_LIMIT,
@@ -148,7 +148,7 @@ describe('Item', () => {
148
148
  <Item
149
149
  {...{
150
150
  ...baseProps,
151
- dayCount: 0,
151
+ dayCount: 1,
152
152
  isSellView: true,
153
153
  item: testItem({ id, highDemandSeasons: [season.SPRING] }),
154
154
  playerInventoryQuantities: { [id]: 4 },
@@ -166,7 +166,7 @@ describe('Item', () => {
166
166
  <Item
167
167
  {...{
168
168
  ...baseProps,
169
- dayCount: 0,
169
+ dayCount: 1,
170
170
  isSellView: true,
171
171
  item: testItem({ id, lowDemandSeasons: [season.SPRING] }),
172
172
  playerInventoryQuantities: { [id]: 4 },
@@ -184,7 +184,7 @@ describe('Item', () => {
184
184
  <Item
185
185
  {...{
186
186
  ...baseProps,
187
- dayCount: 0,
187
+ dayCount: 1,
188
188
  isSellView: true,
189
189
  item: testItem({ id, highDemandSeasons: [season.SUMMER] }),
190
190
  playerInventoryQuantities: { [id]: 4 },
@@ -197,14 +197,14 @@ describe('Item', () => {
197
197
  })
198
198
 
199
199
  test('shows no indicator for a seed sold in the shop, even during its high demand season', () => {
200
- // dayCount 0 is SPRING, carrotSeed's configured high demand season,
200
+ // dayCount 1 is SPRING, carrotSeed's configured high demand season,
201
201
  // but the seasonal price bonus never applies to shop-sold items
202
202
  // (see the #140 guard), so the label must not appear either.
203
203
  render(
204
204
  <Item
205
205
  {...{
206
206
  ...baseProps,
207
- dayCount: 0,
207
+ dayCount: 1,
208
208
  isSellView: true,
209
209
  item: carrotSeed,
210
210
  playerInventoryQuantities: { [carrotSeed.id]: 4 },
@@ -225,7 +225,7 @@ describe('Item', () => {
225
225
  <Item
226
226
  {...{
227
227
  ...baseProps,
228
- dayCount: 0,
228
+ dayCount: 1,
229
229
  isSellView: true,
230
230
  adjustedValue: 10,
231
231
  item: testItem({ id, highDemandSeasons: [season.SPRING] }),
@@ -246,7 +246,7 @@ describe('Item', () => {
246
246
  <Item
247
247
  {...{
248
248
  ...baseProps,
249
- dayCount: 0,
249
+ dayCount: 1,
250
250
  isSellView: true,
251
251
  adjustedValue: 10,
252
252
  item: testItem({ id, lowDemandSeasons: [season.SPRING] }),
@@ -267,7 +267,7 @@ describe('Item', () => {
267
267
  <Item
268
268
  {...{
269
269
  ...baseProps,
270
- dayCount: 0,
270
+ dayCount: 1,
271
271
  isSellView: true,
272
272
  adjustedValue: 10,
273
273
  item: testItem({ id, highDemandSeasons: [season.SUMMER] }),
@@ -40,7 +40,7 @@ vi.mock('../Cellar/index.js', () => ({
40
40
  }))
41
41
 
42
42
  const defaultProps = {
43
- dayCount: 0,
43
+ dayCount: 1,
44
44
  field: [[]],
45
45
  stageFocus: stageFocusType.FIELD,
46
46
  viewTitle: 'Test View',
@@ -156,7 +156,7 @@ describe('Stage', () => {
156
156
 
157
157
  describe('seasonal visual filter', () => {
158
158
  test('applies no filter during spring on the Field screen', () => {
159
- renderWithContext({ stageFocus: stageFocusType.FIELD, dayCount: 0 })
159
+ renderWithContext({ stageFocus: stageFocusType.FIELD, dayCount: 1 })
160
160
 
161
161
  expect(document.querySelector('.stage-background')).toHaveStyle(
162
162
  'filter: none'
@@ -11,7 +11,7 @@ describe('sellItem', () => {
11
11
  const state = sellItem(
12
12
  testState({
13
13
  // Chosen so carrot's SPRING high-demand seasonal bonus doesn't apply.
14
- dayCount: 15,
14
+ dayCount: 16,
15
15
  inventory: [{ id: carrot.id, quantity: 1 }],
16
16
  itemsSold: {},
17
17
  loanBalance: 0,
@@ -59,7 +59,7 @@ describe('sellItem', () => {
59
59
  const state = sellItem(
60
60
  testState({
61
61
  // Chosen so carrot's SPRING high-demand seasonal bonus doesn't apply.
62
- dayCount: 15,
62
+ dayCount: 16,
63
63
  inventory: [{ id: carrot.id, quantity: 1 }],
64
64
  itemsSold: {},
65
65
  loanBalance: 0,
@@ -113,7 +113,7 @@ describe('sellItem', () => {
113
113
  const { learnedRecipes } = sellItem(
114
114
  testState({
115
115
  // Chosen so carrot's SPRING high-demand seasonal bonus doesn't apply.
116
- dayCount: 15,
116
+ dayCount: 16,
117
117
  inventory: [{ id: carrot.id, quantity: 2 }],
118
118
  itemsSold: {},
119
119
  loanBalance: 0,
@@ -172,7 +172,7 @@ describe('sellItem', () => {
172
172
  state = sellItem(
173
173
  testState({
174
174
  // Chosen so carrot's SPRING high-demand seasonal bonus doesn't apply.
175
- dayCount: 15,
175
+ dayCount: 16,
176
176
  inventory: [{ id: carrot.id, quantity: 3 }],
177
177
  itemsSold: {},
178
178
  loanBalance: 100,
@@ -199,7 +199,7 @@ describe('sellItem', () => {
199
199
  state = sellItem(
200
200
  testState({
201
201
  // Chosen so carrot's SPRING high-demand seasonal bonus doesn't apply.
202
- dayCount: 15,
202
+ dayCount: 16,
203
203
  experience: 0,
204
204
  inventory: [{ id: carrot.id, quantity: 3 }],
205
205
  itemsSold: {},
@@ -276,10 +276,10 @@ describe('sellItem', () => {
276
276
 
277
277
  describe('seasonal demand', () => {
278
278
  test('applies a high demand bonus during a crop high demand season', () => {
279
- // dayCount 0 is SPRING, carrot's configured high demand season.
279
+ // dayCount 1 is SPRING, carrot's configured high demand season.
280
280
  const state = sellItem(
281
281
  testState({
282
- dayCount: 0,
282
+ dayCount: 1,
283
283
  inventory: [{ id: carrot.id, quantity: 1 }],
284
284
  itemsSold: {},
285
285
  loanBalance: 0,
@@ -298,14 +298,14 @@ describe('sellItem', () => {
298
298
  })
299
299
 
300
300
  test('bases loan garnishment on the seasonally-adjusted sale price, not the base price', () => {
301
- // dayCount 0 is SPRING, carrot's configured high demand season, so the
301
+ // dayCount 1 is SPRING, carrot's configured high demand season, so the
302
302
  // $25 base value sells for $30. Garnishment is 5% of that $30 (=
303
303
  // $1.50), not 5% of the un-boosted $25 (= $1.25) - otherwise the
304
304
  // effective garnishment rate would drift with the season instead of
305
305
  // staying at a flat LOAN_GARNISHMENT_RATE.
306
306
  const state = sellItem(
307
307
  testState({
308
- dayCount: 0,
308
+ dayCount: 1,
309
309
  inventory: [{ id: carrot.id, quantity: 1 }],
310
310
  itemsSold: {},
311
311
  loanBalance: 100,
@@ -325,10 +325,10 @@ describe('sellItem', () => {
325
325
  })
326
326
 
327
327
  test('applies a low demand penalty during a crop low demand season', () => {
328
- // dayCount 0 is SPRING, corn's configured low demand season.
328
+ // dayCount 1 is SPRING, corn's configured low demand season.
329
329
  const state = sellItem(
330
330
  testState({
331
- dayCount: 0,
331
+ dayCount: 1,
332
332
  inventory: [{ id: corn.id, quantity: 1 }],
333
333
  itemsSold: {},
334
334
  loanBalance: 0,
@@ -347,11 +347,11 @@ describe('sellItem', () => {
347
347
  })
348
348
 
349
349
  test('does not apply the seasonal multiplier to seed sales', () => {
350
- // dayCount 0 is SPRING, which is carrot's high demand season, but this
350
+ // dayCount 1 is SPRING, which is carrot's high demand season, but this
351
351
  // must not apply to selling the seed - see the #140 guard in Item.tsx.
352
352
  const state = sellItem(
353
353
  testState({
354
- dayCount: 0,
354
+ dayCount: 1,
355
355
  inventory: [{ id: carrotSeed.id, quantity: 1 }],
356
356
  itemsSold: {},
357
357
  loanBalance: 0,
@@ -23,7 +23,12 @@ describe('bootup', () => {
23
23
  })
24
24
 
25
25
  await waitFor(() => {
26
- expect(screen.getByText('Day 10', { exact: false })).toBeInTheDocument()
26
+ expect(
27
+ screen.getByText('Day 10', {
28
+ exact: false,
29
+ selector: '.day-and-progress-container span',
30
+ })
31
+ ).toBeInTheDocument()
27
32
  })
28
33
  })
29
34
 
@@ -3,7 +3,12 @@ import userEvent from '@testing-library/user-event'
3
3
 
4
4
  export const waitForBoot = () =>
5
5
  waitFor(() => {
6
- expect(screen.getByText('Day 1', { exact: false })).toBeInTheDocument()
6
+ expect(
7
+ screen.getByText('Day 1', {
8
+ exact: false,
9
+ selector: '.day-and-progress-container span',
10
+ })
11
+ ).toBeInTheDocument()
7
12
  })
8
13
 
9
14
  export const endDay = async () => {
@@ -4,12 +4,12 @@ import { getCurrentSeason } from './getCurrentSeason.js'
4
4
 
5
5
  describe('getCurrentSeason', () => {
6
6
  test.each([
7
- ['returns SPRING for day 0', 0, season.SPRING],
8
- ['returns SPRING for the last day of spring', 14, season.SPRING],
9
- ['returns SUMMER for the first day of summer', 15, season.SUMMER],
10
- ['returns FALL for the first day of fall', 30, season.FALL],
11
- ['returns WINTER for the first day of winter', 45, season.WINTER],
12
- ['wraps back around to SPRING after a full year', 60, season.SPRING],
7
+ ['returns SPRING for day 1', 1, season.SPRING],
8
+ ['returns SPRING for the last day of spring', 15, season.SPRING],
9
+ ['returns SUMMER for the first day of summer', 16, season.SUMMER],
10
+ ['returns FALL for the first day of fall', 31, season.FALL],
11
+ ['returns WINTER for the first day of winter', 46, season.WINTER],
12
+ ['wraps back around to SPRING after a full year', 61, season.SPRING],
13
13
  ] as const)('%s', (_description, dayCount, expectedSeason) => {
14
14
  expect(getCurrentSeason(dayCount)).toEqual(expectedSeason)
15
15
  })
@@ -2,5 +2,10 @@ import { season } from '../enums.js'
2
2
  import { SEASON_ORDER } from '../data/seasons.js'
3
3
  import { SEASON_LENGTH_DAYS } from '../constants.js'
4
4
 
5
+ // dayCount is 1-indexed (the first day of the game is dayCount === 1, per
6
+ // computeStateForNextDay.ts), so it must be shifted to 0-indexed before
7
+ // dividing into season-length chunks.
5
8
  export const getCurrentSeason = (dayCount: number): season =>
6
- SEASON_ORDER[Math.floor(dayCount / SEASON_LENGTH_DAYS) % SEASON_ORDER.length]
9
+ SEASON_ORDER[
10
+ Math.floor((dayCount - 1) / SEASON_LENGTH_DAYS) % SEASON_ORDER.length
11
+ ]
@@ -2,18 +2,18 @@ import { getDayOfSeason } from './getDayOfSeason.js'
2
2
 
3
3
  describe('getDayOfSeason', () => {
4
4
  test('returns 1 for the first day of a season', () => {
5
- expect(getDayOfSeason(0)).toEqual(1)
5
+ expect(getDayOfSeason(1)).toEqual(1)
6
6
  })
7
7
 
8
8
  test('returns the season length for the last day of a season', () => {
9
- expect(getDayOfSeason(14)).toEqual(15)
9
+ expect(getDayOfSeason(15)).toEqual(15)
10
10
  })
11
11
 
12
12
  test('resets to 1 on the first day of the next season', () => {
13
- expect(getDayOfSeason(15)).toEqual(1)
13
+ expect(getDayOfSeason(16)).toEqual(1)
14
14
  })
15
15
 
16
16
  test('continues counting in later seasons', () => {
17
- expect(getDayOfSeason(32)).toEqual(3)
17
+ expect(getDayOfSeason(33)).toEqual(3)
18
18
  })
19
19
  })
@@ -1,4 +1,7 @@
1
1
  import { SEASON_LENGTH_DAYS } from '../constants.js'
2
2
 
3
+ // dayCount is 1-indexed (the first day of the game is dayCount === 1, per
4
+ // computeStateForNextDay.ts), so it must be shifted to 0-indexed before
5
+ // taking the modulus.
3
6
  export const getDayOfSeason = (dayCount: number): number =>
4
- (dayCount % SEASON_LENGTH_DAYS) + 1
7
+ ((dayCount - 1) % SEASON_LENGTH_DAYS) + 1