getExtension(), ['ts', 'tsx'], true)) { continue; } $relative = str_replace($root.'/', '', $file->getPathname()); if ($relative === $allowed) { continue; } foreach (file($file->getPathname()) as $number => $line) { if (preg_match($pattern, $line) === 1) { $offenders[] = $relative.':'.($number + 1); } } } test('dates are never formatted outside the shared helper', function () use ($offenders) { expect($offenders)->toBe([], implode("\n", array_merge( ['These format a date by hand, so they follow the browser rather than the viewer\'s chosen language and timezone.'], ['Use useFormatDate() — date() and dateTime() for instants, calendarDate() for a bare YYYY-MM-DD.'], $offenders, ))); }); test('the helper threads the timezone into every instant it formats', function () use ($root, $allowed) { $source = file_get_contents($root.'/'.$allowed); // The two that render a point in time have to pass timeZone through, or // the whole feature is a setting that changes nothing. expect(substr_count($source, 'timeZone }'))->toBeGreaterThanOrEqual(2); // And the one that renders a calendar date has to pin UTC instead, or a // file's expiry moves a day for everyone west of Greenwich — the bug // that shipped before this existed. expect($source)->toContain("timeZone: 'UTC'"); });