request('POST', '/api/auth/magic-link', ['email' => 'ada@example.com']); self::assertSame(202, $response->getStatusCode()); } public function test_a_magic_link_request_validates_the_address(): void { $response = $this->request('POST', '/api/auth/magic-link', ['email' => 'not-an-email']); self::assertSame(422, $response->getStatusCode()); self::assertArrayHasKey('email', $this->decode($response)['error']['details']); } public function test_opening_the_link_creates_the_account_and_signs_in(): void { $this->request('POST', '/api/auth/magic-link', ['email' => 'Ada@example.com']); $response = $this->request('POST', '/api/auth/verify-email', ['token' => $this->tokenFromEmail()]); self::assertSame(200, $response->getStatusCode()); $body = $this->decode($response); self::assertSame('ada@example.com', $body['user']['email']); self::assertTrue($body['user']['email_verified']); self::assertNotNull($body['user']['email_verified_at']); self::assertNull($body['user']['pending_email']); self::assertArrayNotHasKey('password', $body['user']); self::assertArrayNotHasKey('password_hash', $body['user']); self::assertNotEmpty($body['token']); } public function test_a_second_request_signs_in_the_same_account(): void { $this->request('POST', '/api/auth/magic-link', ['email' => 'ada@example.com']); $firstId = $this->decode( $this->request('POST', '/api/auth/verify-email', ['token' => $this->tokenFromEmail()]), )['user']['id']; $this->db()->prepare('UPDATE users SET verification_email_sent_at = NULL WHERE email = :e') ->execute(['e' => 'ada@example.com']); $this->request('POST', '/api/auth/magic-link', ['email' => 'ADA@EXAMPLE.COM']); $secondId = $this->decode( $this->request('POST', '/api/auth/verify-email', ['token' => $this->tokenFromEmail()]), )['user']['id']; self::assertSame($firstId, $secondId); } public function test_the_link_is_not_sent_again_within_the_resend_interval(): void { $this->request('POST', '/api/auth/magic-link', ['email' => 'ada@example.com']); $response = $this->request('POST', '/api/auth/magic-link', ['email' => 'ada@example.com']); self::assertSame(202, $response->getStatusCode()); self::assertCount(1, $this->sentEmails()); } public function test_me_requires_a_valid_token(): void { $unauthorised = $this->request('GET', '/api/me'); self::assertSame(401, $unauthorised->getStatusCode()); $response = $this->request('GET', '/api/me', null, $this->authHeader('linus@example.com')); self::assertSame(200, $response->getStatusCode()); self::assertSame('linus@example.com', $this->decode($response)['user']['email']); } }