|
54 | 54 | ]; |
55 | 55 |
|
56 | 56 | // Stub a class without a model definition |
57 | | - $stubAction = new class($inputs) extends CreateUserAction { |
| 57 | + $stubAction = new class($inputs) extends CreateUserAction |
| 58 | + { |
58 | 59 | protected string $model = ''; // Intentionally leave model empty |
59 | 60 | }; |
60 | 61 |
|
|
81 | 82 | expect(Hash::check('secretpassword', $record->password))->toBeTrue(); |
82 | 83 | }); |
83 | 84 |
|
| 85 | +// it applies both hashing and encryption to different fields |
| 86 | +it('applies both hashing and encryption to specified fields', function () { |
| 87 | + // Arrange |
| 88 | + $inputs = [ |
| 89 | + 'name' => 'John Doe', |
| 90 | + 'email' => 'johndoe@example.com', |
| 91 | + 'password' => 'secretpassword', |
| 92 | + 'ssn' => '123-45-6789', |
| 93 | + ]; |
| 94 | + |
| 95 | + $action = new CreateUserAction($inputs); |
| 96 | + $action->setProperty('hashFields', ['password']); |
| 97 | + $action->setProperty('encryptFields', ['ssn']); |
| 98 | + |
| 99 | + // Act |
| 100 | + $record = $action->execute(); |
| 101 | + |
| 102 | + // Assert |
| 103 | + expect(Hash::check('secretpassword', $record->password))->toBeTrue(); |
| 104 | + expect(decrypt($record->ssn))->toBe('123-45-6789'); |
| 105 | +}); |
| 106 | + |
| 107 | +// it handles multiple fields for hashing and encryption |
| 108 | +it('handles multiple fields for hashing and encryption', function () { |
| 109 | + // Arrange |
| 110 | + $inputs = [ |
| 111 | + 'name' => 'Jane Doe', |
| 112 | + 'email' => 'janedoe@example.com', |
| 113 | + 'password' => 'anotherpassword', |
| 114 | + 'ssn' => '987-65-4321', |
| 115 | + 'security_answer' => 'My first car', |
| 116 | + ]; |
| 117 | + |
| 118 | + $action = new CreateUserAction($inputs); |
| 119 | + $action->setProperty('hashFields', ['password', 'security_answer']); |
| 120 | + $action->setProperty('encryptFields', ['ssn', 'email']); |
| 121 | + |
| 122 | + // Act |
| 123 | + $record = $action->execute(); |
| 124 | + |
| 125 | + // Assert |
| 126 | + // Only use Hash::check on fields known to be hashed |
| 127 | + expect(Hash::check('anotherpassword', $record->password))->toBeTrue(); |
| 128 | + expect(Hash::check('My first car', $record->security_answer))->toBeTrue(); |
| 129 | + |
| 130 | + // Decrypt and verify the encrypted fields |
| 131 | + expect(decrypt($record->ssn))->toBe('987-65-4321'); |
| 132 | + expect(decrypt($record->email))->toBe('janedoe@example.com'); |
| 133 | +}); |
| 134 | + |
| 135 | +// it applies constraints for update or create |
| 136 | +it('applies constraints for update or create', function () { |
| 137 | + // Arrange |
| 138 | + $inputs = [ |
| 139 | + 'name' => 'John Doe Updated', |
| 140 | + 'email' => 'uniqueemail@example.com', // Use a unique email to avoid the validation error |
| 141 | + 'password' => 'newpassword', |
| 142 | + ]; |
| 143 | + |
| 144 | + // Pre-create a user with a different email to simulate an existing record |
| 145 | + $existingUser = User::create([ |
| 146 | + 'name' => 'Old Name', |
| 147 | + 'email' => 'oldemail@example.com', // Different email to avoid triggering unique constraint |
| 148 | + 'password' => Hash::make('oldpassword'), |
| 149 | + ]); |
| 150 | + |
| 151 | + // Now set the constraints to match the unique constraint check |
| 152 | + $action = new CreateUserAction($inputs); |
| 153 | + $action->setProperty('constrainedBy', ['id' => $existingUser->id]); // Use ID as a unique constraint for update |
| 154 | + |
| 155 | + // Act |
| 156 | + $record = $action->execute(); |
| 157 | + |
| 158 | + // Assert |
| 159 | + expect($record->name)->toBe('John Doe Updated') |
| 160 | + ->and(Hash::check('newpassword', $record->password))->toBeTrue(); |
| 161 | +}); |
| 162 | + |
84 | 163 | // it removes confirmation fields from inputs |
85 | 164 | it('removes confirmation fields from inputs', function () { |
86 | 165 | // Arrange |
|
116 | 195 | $mockConnection = Mockery::mock(); |
117 | 196 | $mockQueryBuilder = Mockery::mock(); |
118 | 197 |
|
119 | | - // Mock the chain of methods on the query builder |
| 198 | + // Set expectation for DB::connection() |
| 199 | + DB::shouldReceive('connection')->once()->andReturn($mockConnection); |
| 200 | + |
| 201 | + // Set up transaction mock and method chaining on the query builder |
| 202 | + DB::shouldReceive('transaction')->once()->andReturnUsing(function ($callback) { |
| 203 | + return $callback(); |
| 204 | + }); |
| 205 | + |
| 206 | + // Set up expectations for methods on the query builder |
120 | 207 | $mockConnection->shouldReceive('table')->andReturn($mockQueryBuilder); |
121 | 208 | $mockQueryBuilder->shouldReceive('useWritePdo')->andReturn($mockQueryBuilder); |
122 | 209 | $mockQueryBuilder->shouldReceive('where')->andReturn($mockQueryBuilder); |
123 | 210 | $mockQueryBuilder->shouldReceive('count')->andReturn(0); |
124 | 211 | $mockQueryBuilder->shouldReceive('updateOrCreate')->andReturn(Mockery::mock(User::class)); |
125 | 212 |
|
126 | | - // Mock the transaction flow |
127 | | - DB::shouldReceive('connection')->andReturn($mockConnection); |
128 | | - DB::shouldReceive('transaction')->once()->andReturnUsing(function ($callback) { |
129 | | - return $callback(); |
130 | | - }); |
131 | | - |
132 | 213 | // Act |
133 | 214 | $record = $action->execute(); |
134 | 215 |
|
135 | 216 | // Assert |
136 | 217 | expect($record)->toBeInstanceOf(User::class); |
137 | 218 | }); |
138 | 219 |
|
139 | | -// it applies encryption to specified fields |
140 | | -it('applies encryption to specified fields', function () { |
| 220 | +// it does not apply transformation if optional field is missing |
| 221 | +it('does not apply transformation if optional field is missing', function () { |
141 | 222 | // Arrange |
142 | 223 | $inputs = [ |
143 | 224 | 'name' => 'John Doe', |
144 | 225 | 'email' => 'johndoe@example.com', |
145 | | - 'password' => 'secretpassword', // password will be hashed |
146 | | - 'ssn' => '123-45-6789', // This is the field to be encrypted |
| 226 | + 'password' => 'secretpassword', // Required field to satisfy validation |
147 | 227 | ]; |
148 | 228 |
|
149 | 229 | $action = new CreateUserAction($inputs); |
150 | | - $action->setProperty('encryptFields', ['ssn']); // Use setProperty to define encryption fields |
| 230 | + $action->setProperty('hashFields', ['security_answer']); // 'security_answer' is not present in inputs |
151 | 231 |
|
152 | 232 | // Act |
153 | 233 | $record = $action->execute(); |
154 | 234 |
|
155 | 235 | // Assert |
156 | | - expect($record)->toBeInstanceOf(User::class); |
157 | | - |
158 | | - // Ensure 'ssn' field was encrypted |
159 | | - $decryptedSSN = decrypt($record->ssn); |
160 | | - expect($decryptedSSN)->toBe('123-45-6789'); |
| 236 | + expect($record)->toBeInstanceOf(User::class); // Check the action executed successfully |
| 237 | + expect($action->inputs())->not->toHaveKey('security_answer'); // Ensure no transformation occurred on missing field |
161 | 238 | }); |
0 commit comments