|
| 1 | +# Migration and Testing Guidelines |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +This document outlines best practices and guidelines for writing migration scripts and their corresponding test cases. |
| 6 | + |
| 7 | +The focus is on ensuring data integrity, handling errors gracefully, and maintaining consistency across our applications versions. |
| 8 | + |
| 9 | +We always look for improvement, if you see anything that could be improved, please open a PR against this guidelines. |
| 10 | + |
| 11 | +You can also check an example of a migration on MetaMask mobile app [here](https://github.com/MetaMask/metamask-mobile/blob/1855bd674e33bb0ece06fb6d8f09a4e5df46a108/app/store/migrations/044.ts#L1) |
| 12 | + |
| 13 | +## Migration Guidelines |
| 14 | + |
| 15 | +1. **State Integrity Checks**: |
| 16 | + |
| 17 | +Validates the state's structure and types before migration, using specific functions to ensure data meets expectations. Halts migration if inconsistencies are detected, preventing data corruption. |
| 18 | + |
| 19 | +- State's on migrations are type `unknown`, it's crucial to validate state integrity before proceeding, we only migrate when structure and types meets our expectations, |
| 20 | +- Validate the state and its nested properties using functions like `isObject` and `hasProperty` from `@metamask/utils`, |
| 21 | +- Prevent data corruption by halting the migration on any inconsistencies and logging errors. |
| 22 | + |
| 23 | +2. **Error Handling**: |
| 24 | + |
| 25 | +Logs detailed errors and halts the migration if potential data corruption is identified, ensuring issues are addressed before proceeding. |
| 26 | + |
| 27 | +- Log errors with `captureException` from Sentry, which is crucial for diagnosing issues post-migration, |
| 28 | +- Ensure that error messages are descriptive: include the migration number and a clear description of the issue, |
| 29 | +- If an exception is detected, indicating potential data corruption, halt the migration process and return the intial state, |
| 30 | + |
| 31 | +3. **Return State**: |
| 32 | + |
| 33 | +Completes the migration by returning the state, modified or not, ensuring a seamless transition to subsequent migrations. |
| 34 | + |
| 35 | +- Always return the state at the end of the migration function, whether it was modified or not, |
| 36 | +- Returning the state ensures that the migration process completes and the state is passed to the next migrations. |
| 37 | + |
| 38 | +## Testing Guidelines |
| 39 | + |
| 40 | +1. **Initial State Setup**: |
| 41 | + |
| 42 | +- Create an initial state that reflects possible real-world scenarios, including edge cases, |
| 43 | +- if needed, create multiple initial states and use them each in a test for this specific case, |
| 44 | + |
| 45 | +2. **Invalid State Scenarios**: |
| 46 | + |
| 47 | +- Test how the migration handles invalid states, including null values, incorrect types, and missing properties, |
| 48 | +- Ensure that the migration logs the appropriate errors without modifying and corrupting the state. |
| 49 | + |
| 50 | +3. **Error Assertions**: |
| 51 | + |
| 52 | +- Verify that errors are logged correctly for invalid states or unexpected conditions, |
| 53 | + |
| 54 | +4. **Ensure State Immutability**: |
| 55 | + |
| 56 | +- Always use deep cloning on the old state before passing it to the migration function in tests. For example, use `cloneDeep` from `lodash`. |
| 57 | + - Deep cloning preserves the integrity of your test data across different test cases. |
| 58 | + - Ensures the original state object is not mutated during the migration process. |
| 59 | + - guarantees that each test case runs on an correct, clean copy of the state. |
| 60 | +- Never mutate the state directly as this can: |
| 61 | + - lead to hard-to-track bugs and false positives or negatives test results. |
| 62 | + - start subsequent tests with the original state as intended. |
0 commit comments