toBe('Navn'); expect(newsletterT('submit_button'))->toBe('Meld deg på'); expect(newsletterT('success_message'))->toBe('Sjekk innboksen din!'); }); it('returns the key itself for an unknown key when no context is present', function () { unset($GLOBALS['ctx']); expect(newsletterT('nonexistent_key'))->toBe('nonexistent_key'); }); it('returns a translation from context when available', function () { $GLOBALS['ctx'] = new class { public function get(string $key, mixed $default = null): mixed { return $key === 'translations' ? ['newsletter.name_label' => 'Name'] : $default; } }; expect(newsletterT('name_label'))->toBe('Name'); unset($GLOBALS['ctx']); }); it('falls back to the key when context has no matching translation', function () { $GLOBALS['ctx'] = new class { public function get(string $key, mixed $default = null): mixed { return $key === 'translations' ? [] : $default; } }; expect(newsletterT('name_label'))->toBe('name_label'); unset($GLOBALS['ctx']); }); // --- newsletterCheckRateLimit --- it('returns true when no previous submission is recorded in the session', function () { unset($_SESSION['newsletter_last_submit']); expect(newsletterCheckRateLimit())->toBeTrue(); }); it('returns false immediately after a submission', function () { $_SESSION['newsletter_last_submit'] = time(); expect(newsletterCheckRateLimit())->toBeFalse(); }); it('returns false when 29 seconds have elapsed', function () { $_SESSION['newsletter_last_submit'] = time() - 29; expect(newsletterCheckRateLimit())->toBeFalse(); }); it('returns true when exactly 30 seconds have elapsed', function () { $_SESSION['newsletter_last_submit'] = time() - 30; expect(newsletterCheckRateLimit())->toBeTrue(); }); it('returns true when more than 30 seconds have elapsed', function () { $_SESSION['newsletter_last_submit'] = time() - 60; expect(newsletterCheckRateLimit())->toBeTrue(); }); // --- newsletterGetTranslations --- it('returns all expected translation keys', function () { unset($GLOBALS['ctx']); expect(newsletterGetTranslations())->toHaveKeys([ 'nameLabel', 'namePlaceholder', 'emailLabel', 'emailPlaceholder', 'notice', 'submitButton', 'successMessage', 'successConfirm', 'errorMessage', ]); }); it('HTML-escapes special characters in translation values', function () { $GLOBALS['ctx'] = new class { public function get(string $key, mixed $default = null): mixed { return $key === 'translations' ? ['newsletter.name_label' => 'Name & "Label"'] : $default; } }; $translations = newsletterGetTranslations(); expect($translations['nameLabel'])->toBe('<b>Name & "Label"</b>'); unset($GLOBALS['ctx']); }); it('returns string values for all keys', function () { unset($GLOBALS['ctx']); foreach (newsletterGetTranslations() as $key => $value) { expect($value)->toBeString("Key '{$key}' should be a string"); } });