integration tests
This commit is contained in:
@@ -2,456 +2,83 @@
|
||||
* Integration Test: Onboarding Personal Information Use Case Orchestration
|
||||
*
|
||||
* Tests the orchestration logic of personal information-related Use Cases:
|
||||
* - ValidatePersonalInfoUseCase: Validates personal information
|
||||
* - SavePersonalInfoUseCase: Saves personal information to repository
|
||||
* - UpdatePersonalInfoUseCase: Updates existing personal information
|
||||
* - GetPersonalInfoUseCase: Retrieves personal information
|
||||
* - CompleteDriverOnboardingUseCase: Handles the initial driver profile creation
|
||||
*
|
||||
* Validates that Use Cases correctly interact with their Ports (Repositories, Event Publishers)
|
||||
* Validates that Use Cases correctly interact with their Ports (Repositories)
|
||||
* Uses In-Memory adapters for fast, deterministic testing
|
||||
*
|
||||
* Focus: Business logic orchestration, NOT UI rendering
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
|
||||
import { InMemoryUserRepository } from '../../../adapters/users/persistence/inmemory/InMemoryUserRepository';
|
||||
import { InMemoryEventPublisher } from '../../../adapters/events/InMemoryEventPublisher';
|
||||
import { ValidatePersonalInfoUseCase } from '../../../core/onboarding/use-cases/ValidatePersonalInfoUseCase';
|
||||
import { SavePersonalInfoUseCase } from '../../../core/onboarding/use-cases/SavePersonalInfoUseCase';
|
||||
import { UpdatePersonalInfoUseCase } from '../../../core/onboarding/use-cases/UpdatePersonalInfoUseCase';
|
||||
import { GetPersonalInfoUseCase } from '../../../core/onboarding/use-cases/GetPersonalInfoUseCase';
|
||||
import { PersonalInfoCommand } from '../../../core/onboarding/ports/PersonalInfoCommand';
|
||||
import { PersonalInfoQuery } from '../../../core/onboarding/ports/PersonalInfoQuery';
|
||||
import { describe, it, expect, beforeAll, beforeEach } from 'vitest';
|
||||
import { InMemoryDriverRepository } from '../../../adapters/racing/persistence/inmemory/InMemoryDriverRepository';
|
||||
import { CompleteDriverOnboardingUseCase } from '../../../core/racing/application/use-cases/CompleteDriverOnboardingUseCase';
|
||||
import { Logger } from '../../../core/shared/domain/Logger';
|
||||
|
||||
describe('Onboarding Personal Information Use Case Orchestration', () => {
|
||||
let userRepository: InMemoryUserRepository;
|
||||
let eventPublisher: InMemoryEventPublisher;
|
||||
let validatePersonalInfoUseCase: ValidatePersonalInfoUseCase;
|
||||
let savePersonalInfoUseCase: SavePersonalInfoUseCase;
|
||||
let updatePersonalInfoUseCase: UpdatePersonalInfoUseCase;
|
||||
let getPersonalInfoUseCase: GetPersonalInfoUseCase;
|
||||
let driverRepository: InMemoryDriverRepository;
|
||||
let completeDriverOnboardingUseCase: CompleteDriverOnboardingUseCase;
|
||||
let mockLogger: Logger;
|
||||
|
||||
beforeAll(() => {
|
||||
// TODO: Initialize In-Memory repositories and event publisher
|
||||
// userRepository = new InMemoryUserRepository();
|
||||
// eventPublisher = new InMemoryEventPublisher();
|
||||
// validatePersonalInfoUseCase = new ValidatePersonalInfoUseCase({
|
||||
// userRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// savePersonalInfoUseCase = new SavePersonalInfoUseCase({
|
||||
// userRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// updatePersonalInfoUseCase = new UpdatePersonalInfoUseCase({
|
||||
// userRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
// getPersonalInfoUseCase = new GetPersonalInfoUseCase({
|
||||
// userRepository,
|
||||
// eventPublisher,
|
||||
// });
|
||||
mockLogger = {
|
||||
info: () => {},
|
||||
debug: () => {},
|
||||
warn: () => {},
|
||||
error: () => {},
|
||||
} as unknown as Logger;
|
||||
|
||||
driverRepository = new InMemoryDriverRepository(mockLogger);
|
||||
completeDriverOnboardingUseCase = new CompleteDriverOnboardingUseCase(
|
||||
driverRepository,
|
||||
mockLogger
|
||||
);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// TODO: Clear all In-Memory repositories before each test
|
||||
// userRepository.clear();
|
||||
// eventPublisher.clear();
|
||||
beforeEach(async () => {
|
||||
await driverRepository.clear();
|
||||
});
|
||||
|
||||
describe('ValidatePersonalInfoUseCase - Success Path', () => {
|
||||
it('should validate personal info with all required fields', async () => {
|
||||
// TODO: Implement test
|
||||
describe('CompleteDriverOnboardingUseCase - Personal Info Scenarios', () => {
|
||||
it('should create driver with valid personal information', async () => {
|
||||
// Scenario: Valid personal info
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with valid personal info
|
||||
// Then: Validation should pass
|
||||
// And: EventPublisher should emit PersonalInfoValidatedEvent
|
||||
// Given: A new user
|
||||
const input = {
|
||||
userId: 'user-789',
|
||||
firstName: 'Alice',
|
||||
lastName: 'Wonderland',
|
||||
displayName: 'AliceRacer',
|
||||
country: 'UK',
|
||||
};
|
||||
|
||||
// When: CompleteDriverOnboardingUseCase.execute() is called
|
||||
const result = await completeDriverOnboardingUseCase.execute(input);
|
||||
|
||||
// Then: Validation should pass and driver be created
|
||||
expect(result.isOk()).toBe(true);
|
||||
const { driver } = result.unwrap();
|
||||
expect(driver.name.toString()).toBe('AliceRacer');
|
||||
expect(driver.country.toString()).toBe('UK');
|
||||
});
|
||||
|
||||
it('should validate personal info with minimum length display name', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Minimum length display name
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with 3-character display name
|
||||
// Then: Validation should pass
|
||||
// And: EventPublisher should emit PersonalInfoValidatedEvent
|
||||
});
|
||||
it('should handle bio as optional personal information', async () => {
|
||||
// Scenario: Optional bio field
|
||||
// Given: Personal info with bio
|
||||
const input = {
|
||||
userId: 'user-bio',
|
||||
firstName: 'Bob',
|
||||
lastName: 'Builder',
|
||||
displayName: 'BobBuilds',
|
||||
country: 'AU',
|
||||
bio: 'I build fast cars',
|
||||
};
|
||||
|
||||
it('should validate personal info with maximum length display name', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Maximum length display name
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with 50-character display name
|
||||
// Then: Validation should pass
|
||||
// And: EventPublisher should emit PersonalInfoValidatedEvent
|
||||
});
|
||||
// When: CompleteDriverOnboardingUseCase.execute() is called
|
||||
const result = await completeDriverOnboardingUseCase.execute(input);
|
||||
|
||||
it('should validate personal info with special characters in display name', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Special characters in display name
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with display name containing special characters
|
||||
// Then: Validation should pass
|
||||
// And: EventPublisher should emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should validate personal info with various countries', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Various countries
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with different countries
|
||||
// Then: Validation should pass
|
||||
// And: EventPublisher should emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should validate personal info with various timezones', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Various timezones
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with different timezones
|
||||
// Then: Validation should pass
|
||||
// And: EventPublisher should emit PersonalInfoValidatedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('ValidatePersonalInfoUseCase - Validation', () => {
|
||||
it('should reject personal info with empty first name', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Empty first name
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with empty first name
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should reject personal info with empty last name', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Empty last name
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with empty last name
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should reject personal info with empty display name', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Empty display name
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with empty display name
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should reject personal info with display name too short', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Display name too short
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with display name less than 3 characters
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should reject personal info with display name too long', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Display name too long
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with display name more than 50 characters
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should reject personal info with empty country', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Empty country
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with empty country
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should reject personal info with invalid characters in first name', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Invalid characters in first name
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with numbers in first name
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should reject personal info with invalid characters in last name', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Invalid characters in last name
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with numbers in last name
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should reject personal info with profanity in display name', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Profanity in display name
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with profanity in display name
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should reject personal info with duplicate display name', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Duplicate display name
|
||||
// Given: A user with display name "RacerJohn" already exists
|
||||
// And: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with display name "RacerJohn"
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should reject personal info with display name containing only spaces', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Display name with only spaces
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with display name containing only spaces
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should reject personal info with display name with leading/trailing spaces', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Display name with leading/trailing spaces
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with display name " John "
|
||||
// Then: Should throw ValidationError (after trimming)
|
||||
// And: EventPublisher should NOT emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should reject personal info with email format in display name', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Email format in display name
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with email in display name
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit PersonalInfoValidatedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('SavePersonalInfoUseCase - Success Path', () => {
|
||||
it('should save personal info with all required fields', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Save valid personal info
|
||||
// Given: A new user exists
|
||||
// And: Personal info is validated
|
||||
// When: SavePersonalInfoUseCase.execute() is called with valid personal info
|
||||
// Then: Personal info should be saved
|
||||
// And: EventPublisher should emit PersonalInfoSavedEvent
|
||||
});
|
||||
|
||||
it('should save personal info with optional fields', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Save personal info with optional fields
|
||||
// Given: A new user exists
|
||||
// And: Personal info is validated
|
||||
// When: SavePersonalInfoUseCase.execute() is called with optional fields
|
||||
// Then: Personal info should be saved
|
||||
// And: Optional fields should be saved
|
||||
// And: EventPublisher should emit PersonalInfoSavedEvent
|
||||
});
|
||||
|
||||
it('should save personal info with different timezones', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Save personal info with different timezones
|
||||
// Given: A new user exists
|
||||
// And: Personal info is validated
|
||||
// When: SavePersonalInfoUseCase.execute() is called with different timezones
|
||||
// Then: Personal info should be saved
|
||||
// And: Timezone should be saved correctly
|
||||
// And: EventPublisher should emit PersonalInfoSavedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('SavePersonalInfoUseCase - Validation', () => {
|
||||
it('should reject saving personal info without validation', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Save without validation
|
||||
// Given: A new user exists
|
||||
// When: SavePersonalInfoUseCase.execute() is called without validation
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit PersonalInfoSavedEvent
|
||||
});
|
||||
|
||||
it('should reject saving personal info for already onboarded user', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Already onboarded user
|
||||
// Given: A user has already completed onboarding
|
||||
// When: SavePersonalInfoUseCase.execute() is called
|
||||
// Then: Should throw AlreadyOnboardedError
|
||||
// And: EventPublisher should NOT emit PersonalInfoSavedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('UpdatePersonalInfoUseCase - Success Path', () => {
|
||||
it('should update personal info with valid data', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Update personal info
|
||||
// Given: A user exists with personal info
|
||||
// When: UpdatePersonalInfoUseCase.execute() is called with new valid data
|
||||
// Then: Personal info should be updated
|
||||
// And: EventPublisher should emit PersonalInfoUpdatedEvent
|
||||
});
|
||||
|
||||
it('should update personal info with partial data', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Update with partial data
|
||||
// Given: A user exists with personal info
|
||||
// When: UpdatePersonalInfoUseCase.execute() is called with partial data
|
||||
// Then: Only specified fields should be updated
|
||||
// And: EventPublisher should emit PersonalInfoUpdatedEvent
|
||||
});
|
||||
|
||||
it('should update personal info with timezone change', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Update timezone
|
||||
// Given: A user exists with personal info
|
||||
// When: UpdatePersonalInfoUseCase.execute() is called with new timezone
|
||||
// Then: Timezone should be updated
|
||||
// And: EventPublisher should emit PersonalInfoUpdatedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('UpdatePersonalInfoUseCase - Validation', () => {
|
||||
it('should reject update with invalid data', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Invalid update data
|
||||
// Given: A user exists with personal info
|
||||
// When: UpdatePersonalInfoUseCase.execute() is called with invalid data
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit PersonalInfoUpdatedEvent
|
||||
});
|
||||
|
||||
it('should reject update for non-existent user', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Non-existent user
|
||||
// Given: No user exists
|
||||
// When: UpdatePersonalInfoUseCase.execute() is called
|
||||
// Then: Should throw UserNotFoundError
|
||||
// And: EventPublisher should NOT emit PersonalInfoUpdatedEvent
|
||||
});
|
||||
|
||||
it('should reject update with duplicate display name', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Duplicate display name
|
||||
// Given: User A has display name "RacerJohn"
|
||||
// And: User B exists
|
||||
// When: UpdatePersonalInfoUseCase.execute() is called for User B with display name "RacerJohn"
|
||||
// Then: Should throw ValidationError
|
||||
// And: EventPublisher should NOT emit PersonalInfoUpdatedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetPersonalInfoUseCase - Success Path', () => {
|
||||
it('should retrieve personal info for existing user', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Retrieve personal info
|
||||
// Given: A user exists with personal info
|
||||
// When: GetPersonalInfoUseCase.execute() is called
|
||||
// Then: Personal info should be returned
|
||||
// And: EventPublisher should emit PersonalInfoRetrievedEvent
|
||||
});
|
||||
|
||||
it('should retrieve personal info with all fields', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Retrieve with all fields
|
||||
// Given: A user exists with complete personal info
|
||||
// When: GetPersonalInfoUseCase.execute() is called
|
||||
// Then: All personal info fields should be returned
|
||||
// And: EventPublisher should emit PersonalInfoRetrievedEvent
|
||||
});
|
||||
|
||||
it('should retrieve personal info with minimal fields', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Retrieve with minimal fields
|
||||
// Given: A user exists with minimal personal info
|
||||
// When: GetPersonalInfoUseCase.execute() is called
|
||||
// Then: Available personal info fields should be returned
|
||||
// And: EventPublisher should emit PersonalInfoRetrievedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetPersonalInfoUseCase - Validation', () => {
|
||||
it('should reject retrieval for non-existent user', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Non-existent user
|
||||
// Given: No user exists
|
||||
// When: GetPersonalInfoUseCase.execute() is called
|
||||
// Then: Should throw UserNotFoundError
|
||||
// And: EventPublisher should NOT emit PersonalInfoRetrievedEvent
|
||||
});
|
||||
|
||||
it('should reject retrieval for user without personal info', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: User without personal info
|
||||
// Given: A user exists without personal info
|
||||
// When: GetPersonalInfoUseCase.execute() is called
|
||||
// Then: Should throw PersonalInfoNotFoundError
|
||||
// And: EventPublisher should NOT emit PersonalInfoRetrievedEvent
|
||||
});
|
||||
});
|
||||
|
||||
describe('Personal Info Orchestration - Error Handling', () => {
|
||||
it('should handle repository errors gracefully', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Repository error
|
||||
// Given: UserRepository throws an error
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called
|
||||
// Then: Should propagate the error appropriately
|
||||
// And: EventPublisher should NOT emit any events
|
||||
});
|
||||
|
||||
it('should handle concurrent updates gracefully', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Concurrent updates
|
||||
// Given: A user exists with personal info
|
||||
// When: UpdatePersonalInfoUseCase.execute() is called multiple times concurrently
|
||||
// Then: Updates should be handled appropriately
|
||||
// And: EventPublisher should emit appropriate events
|
||||
});
|
||||
});
|
||||
|
||||
describe('Personal Info Orchestration - Edge Cases', () => {
|
||||
it('should handle timezone edge cases', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Edge case timezones
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with edge case timezones
|
||||
// Then: Validation should pass
|
||||
// And: EventPublisher should emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should handle country edge cases', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Edge case countries
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with edge case countries
|
||||
// Then: Validation should pass
|
||||
// And: EventPublisher should emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should handle display name edge cases', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Edge case display names
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with edge case display names
|
||||
// Then: Validation should pass
|
||||
// And: EventPublisher should emit PersonalInfoValidatedEvent
|
||||
});
|
||||
|
||||
it('should handle special characters in names', async () => {
|
||||
// TODO: Implement test
|
||||
// Scenario: Special characters in names
|
||||
// Given: A new user exists
|
||||
// When: ValidatePersonalInfoUseCase.execute() is called with special characters in names
|
||||
// Then: Validation should pass
|
||||
// And: EventPublisher should emit PersonalInfoValidatedEvent
|
||||
// Then: Bio should be saved
|
||||
expect(result.isOk()).toBe(true);
|
||||
expect(result.unwrap().driver.bio?.toString()).toBe('I build fast cars');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user