While making an unrelated change — adding a processor to a privacy page and a link to a footer — the test suite came back with eleven passes and one failure:
An episode airing tomorrow was being counted as two days away. That is about as load-bearing as a bug gets in an app whose entire purpose is telling you when the next episode airs.
It turned out the countdown was fine. The test was wrong, in a way that made it fail for roughly a third of every day and pass for the rest.
The edited files were a privacy page, a footer and a markdown document. The failing test covers air-date arithmetic. Those are obviously unrelated — but "obviously unrelated" is a hypothesis, and the cost of checking it is one command:
Identical failure with the changes removed. That single result reframes everything that follows: this is not a regression being debugged, it is an existing defect being discovered. Without it, the natural next move is to start reading your own diff for a cause that was never in it — and the worst outcome of that search is "fixing" code of your own that was correct.
A test about day counting failing intermittently points at timezones, so the first suspect is the machine's own zone. That is easy to test by simply telling the process it lives somewhere else:
Both fail, identically. That is a useful negative: the host timezone changes what the process calls local time, but it does not change the instant at which the test runs. So the hidden dependency is not where the test runs. It is when.
Here is the test as written. It builds "tomorrow" and "yesterday" by adding and subtracting a day in milliseconds, then trimming the result to a date:
That looks unimpeachable, and it contains the whole bug. toISOString() always formats in UTC. So the date handed to the function is "tomorrow according to UTC".
The function, though, deliberately does not count days in UTC. It counts them in the show's own country's timezone, and for a US show that means America/LosAngeles. That choice is not an accident or an oversight — it is the fix for an earlier bug where a show's card and its notification disagreed about whether the same episode aired today or tomorrow, because one of them mixed the viewer's timezone into the comparison.
So the test measures from one calendar and the function measures from another. For most of the day they agree. For the hours when UTC has already rolled over to a new date and Los Angeles has not, they do not:
| Moment | Test asks about | Function's today | Result | |---|---|---|---| | 15:00 UTC, 11 Sept | 12 Sept | 11 Sept (LA) | 1 ✓ | | 06:39 UTC, 12 Sept | 13 Sept | 11 Sept (LA) | 2 ✗ |
At 06:39 UTC on 12 September it is still 23:39 on 11 September in Los Angeles. UTC's "tomorrow" is 13 September. Los Angeles's "today" is the 11th. Two days apart, and the assertion wanted one.
The failure window is exactly the offset between the two zones: seven hours while Los Angeles is on daylight time, eight hours when it isn't. Midnight UTC to around 07:00 UTC, every single day. After that it goes green again on its own.
Two things about that are worse than an ordinary broken test. The first is that it presents as a feature bug — the assertion says an episode airing tomorrow is being counted as two days out, which is precisely what a real off-by-one in the countdown would look like. The second is that re-running it later makes it pass, which quietly teaches everyone that it is "flaky" and can be re-run rather than read.
The repair is to build the fixture in the same frame the function measures in, rather than in UTC:
The zone is looked up from the same table the application uses, so the test does not hardcode a mapping that could later drift out of step with the code.
That has a real cost worth naming: because the fixture now derives its zone from the same table as the code under test, this test can no longer catch a wrong entry in that table. It is not trying to. Its job is the day arithmetic, and covering the mapping is a different test with fixed, hand-written dates. A test that quietly tests two things is how you end up with one that fails for reasons its name doesn't explain.
