Skip to content

Commit

Permalink
chore: transfer ownership of auth & profile sync E2E from notificatio…
Browse files Browse the repository at this point in the history
…ns to identity (#12569)

## **Description**

This PR takes care of all the necessary changes in order to decouple
Auth & Profile Sync E2E from the notifications feature.
This also underlines the ownership change from @MetaMask/notifications
to @MetaMask/identity.

The changes made here will help transitioning to cleaner separation of
concerns for features leveraging profile sync (i.e Notifications,
Account syncing...).

⚠️ This PR does not add missing tests nor introduces any changes. This
is only moving files around and separating concerns.
☝️ This PR has the "No E2E Smoke Needed" label since, even though we're
moving e2e files, these E2E tests are not ran yet (they were - and still
are - commented in `bitrise.yml`)

## **Related issues**

Fixes:

## **Manual testing steps**

No testing steps since this PR does not change the implementation of
existing features.

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
  • Loading branch information
mathieuartu authored Dec 5, 2024
1 parent 011560f commit fcb68ad
Show file tree
Hide file tree
Showing 12 changed files with 119 additions and 49 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ app/store/util/notifications @MetaMask/notifications
app/actions/identity @MetaMask/identity
app/util/identity @MetaMask/identity
app/components/UI/ProfileSyncing @MetaMask/identity
e2e/specs/identity @MetaMask/identity

# LavaMoat Team
ses.cjs @MetaMask/supply-chain
Expand Down
20 changes: 10 additions & 10 deletions bitrise.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ stages:
- run_ios_api_specs: {}
- run_tag_smoke_accounts_ios: {}
- run_tag_smoke_accounts_android: {}
# - run_tag_smoke_notifications_ios: {}
# - run_tag_smoke_notifications_android: {}
# - run_tag_smoke_identity_ios: {}
# - run_tag_smoke_identity_android: {}
# - run_tag_smoke_assets_ios: {}
- run_tag_smoke_assets_android: {}
- run_tag_smoke_confirmations_ios: {}
Expand All @@ -177,8 +177,8 @@ stages:
- run_tag_smoke_confirmations_android: {}
- run_tag_smoke_accounts_ios: {}
- run_tag_smoke_accounts_android: {}
# - run_tag_smoke_notifications_ios: {}
# - run_tag_smoke_notifications_android: {}
# - run_tag_smoke_identity_ios: {}
# - run_tag_smoke_identity_android: {}
# - run_tag_smoke_assets_ios: {}
- run_tag_smoke_assets_android: {}
# - run_tag_smoke_swaps_ios: {}
Expand Down Expand Up @@ -595,20 +595,20 @@ workflows:
- TEST_SUITE_TAG: '.*SmokeAccounts.*'
after_run:
- android_e2e_test
run_tag_smoke_notifications_ios:
run_tag_smoke_identity_ios:
envs:
- TEST_SUITE_FOLDER: './e2e/specs/notifications/*'
- TEST_SUITE_TAG: '.*SmokeNotifications.*'
- TEST_SUITE_FOLDER: './e2e/specs/identity/*'
- TEST_SUITE_TAG: '.*SmokeIdentity.*'
after_run:
- ios_e2e_test
run_tag_smoke_notifications_android:
run_tag_smoke_identity_android:
meta:
bitrise.io:
stack: linux-docker-android-22.04
machine_type_id: elite-xl
envs:
- TEST_SUITE_FOLDER: './e2e/specs/notifications/*'
- TEST_SUITE_TAG: '.*SmokeNotifications.*'
- TEST_SUITE_FOLDER: './e2e/specs/identity/*'
- TEST_SUITE_TAG: '.*SmokeIdentity.*'
after_run:
- android_e2e_test
run_tag_smoke_assets_ios:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { SDK } from '@metamask/profile-sync-controller';
import {
NOTIFICATIONS_TEAM_PASSWORD,
NOTIFICATIONS_TEAM_SEED_PHRASE,
NOTIFICATIONS_TEAM_STORAGE_KEY,
IDENTITY_TEAM_PASSWORD,
IDENTITY_TEAM_SEED_PHRASE,
IDENTITY_TEAM_STORAGE_KEY,
} from '../utils/constants';
import {
startMockServer,
Expand All @@ -16,10 +16,10 @@ import AccountListBottomSheet from '../../../pages/wallet/AccountListBottomSheet
import Assertions from '../../../utils/Assertions';
import AddAccountBottomSheet from '../../../pages/wallet/AddAccountBottomSheet';
import AccountActionsBottomSheet from '../../../pages/wallet/AccountActionsBottomSheet';
import { mockNotificationServices } from '../utils/mocks';
import { SmokeNotifications } from '../../../tags';
import { mockIdentityServices } from '../utils/mocks';
import { SmokeIdentity } from '../../../tags';

describe(SmokeNotifications('Account syncing'), () => {
describe(SmokeIdentity('Account syncing'), () => {
const NEW_ACCOUNT_NAME = 'My third account';
let decryptedAccountNames = '';

Expand All @@ -29,8 +29,9 @@ describe(SmokeNotifications('Account syncing'), () => {

const mockServer = await startMockServer();

const { userStorageMockttpControllerInstance } =
await mockNotificationServices(mockServer);
const { userStorageMockttpControllerInstance } = await mockIdentityServices(
mockServer,
);

userStorageMockttpControllerInstance.setupPath('accounts', mockServer, {
getResponse: accountsSyncMockResponse,
Expand All @@ -40,7 +41,7 @@ describe(SmokeNotifications('Account syncing'), () => {
accountsSyncMockResponse.map(async (response) => {
const decryptedAccountName = await SDK.Encryption.decryptString(
response.Data,
NOTIFICATIONS_TEAM_STORAGE_KEY,
IDENTITY_TEAM_STORAGE_KEY,
);
return JSON.parse(decryptedAccountName).n;
}),
Expand All @@ -58,8 +59,8 @@ describe(SmokeNotifications('Account syncing'), () => {

it('syncs newly added accounts with custom names', async () => {
await importWalletWithRecoveryPhrase(
NOTIFICATIONS_TEAM_SEED_PHRASE,
NOTIFICATIONS_TEAM_PASSWORD,
IDENTITY_TEAM_SEED_PHRASE,
IDENTITY_TEAM_PASSWORD,
);

await WalletView.tapIdenticon();
Expand Down Expand Up @@ -94,8 +95,8 @@ describe(SmokeNotifications('Account syncing'), () => {
});

await importWalletWithRecoveryPhrase(
NOTIFICATIONS_TEAM_SEED_PHRASE,
NOTIFICATIONS_TEAM_PASSWORD,
IDENTITY_TEAM_SEED_PHRASE,
IDENTITY_TEAM_PASSWORD,
);

await WalletView.tapIdenticon();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { SDK } from '@metamask/profile-sync-controller';
import {
NOTIFICATIONS_TEAM_PASSWORD,
NOTIFICATIONS_TEAM_SEED_PHRASE,
NOTIFICATIONS_TEAM_STORAGE_KEY,
IDENTITY_TEAM_PASSWORD,
IDENTITY_TEAM_SEED_PHRASE,
IDENTITY_TEAM_STORAGE_KEY,
} from '../utils/constants';
import {
startMockServer,
Expand All @@ -14,17 +14,18 @@ import TestHelpers from '../../../helpers';
import WalletView from '../../../pages/wallet/WalletView';
import AccountListBottomSheet from '../../../pages/wallet/AccountListBottomSheet';
import Assertions from '../../../utils/Assertions';
import { mockNotificationServices } from '../utils/mocks';
import { SmokeNotifications } from '../../../tags';
import { mockIdentityServices } from '../utils/mocks';
import { SmokeIdentity } from '../../../tags';

describe(SmokeNotifications('Account syncing'), () => {
describe(SmokeIdentity('Account syncing'), () => {
beforeAll(async () => {
const mockServer = await startMockServer({
mockUrl: 'https://user-storage.api.cx.metamask.io/api/v1/userstorage',
});

const { userStorageMockttpControllerInstance } =
await mockNotificationServices(mockServer);
const { userStorageMockttpControllerInstance } = await mockIdentityServices(
mockServer,
);

userStorageMockttpControllerInstance.setupPath('accounts', mockServer, {
getResponse: accountsSyncMockResponse,
Expand All @@ -48,15 +49,15 @@ describe(SmokeNotifications('Account syncing'), () => {
accountsSyncMockResponse.map(async (response) => {
const decryptedAccountName = await SDK.Encryption.decryptString(
response.Data,
NOTIFICATIONS_TEAM_STORAGE_KEY,
IDENTITY_TEAM_STORAGE_KEY,
);
return JSON.parse(decryptedAccountName).n;
}),
);

await importWalletWithRecoveryPhrase(
NOTIFICATIONS_TEAM_SEED_PHRASE,
NOTIFICATIONS_TEAM_PASSWORD,
IDENTITY_TEAM_SEED_PHRASE,
IDENTITY_TEAM_PASSWORD,
);

await WalletView.tapIdenticon();
Expand Down
7 changes: 7 additions & 0 deletions e2e/specs/identity/utils/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// As we rely on profile syncing for most of our features, we need to use the same SRP for all of our tests
export const IDENTITY_TEAM_SEED_PHRASE =
'leisure swallow trip elbow prison wait rely keep supply hole general mountain';
export const IDENTITY_TEAM_PASSWORD = 'notify_password';
// You can use the storage key below to generate mock data
export const IDENTITY_TEAM_STORAGE_KEY =
'0d55d30da233959674d14076737198c05ae3fb8631a17e20d3c28c60dddd82f7';
10 changes: 10 additions & 0 deletions e2e/specs/identity/utils/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const determineIfFeatureEntryFromURL = (url) => {
const decodedUrl = decodeURIComponent(url);
return (
decodedUrl.substring(decodedUrl.lastIndexOf('userstorage') + 12).split('/')
.length === 2
);
};

export const getDecodedProxiedURL = (url) =>
decodeURIComponent(String(new URL(url).searchParams.get('url')));
60 changes: 60 additions & 0 deletions e2e/specs/identity/utils/mocks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { AuthenticationController } from '@metamask/profile-sync-controller';
import { UserStorageMockttpController } from './user-storage/userStorageMockttpController';
import { getDecodedProxiedURL } from './helpers';

const AuthMocks = AuthenticationController.Mocks;

/**
* E2E mock setup for identity APIs (Auth, UserStorage, Profile syncing)
*
* @param server - server obj used to mock our endpoints
* @param userStorageMockttpController - optional controller to mock user storage endpoints
*/
export async function mockIdentityServices(server) {
// Auth
mockAPICall(server, AuthMocks.getMockAuthNonceResponse());
mockAPICall(server, AuthMocks.getMockAuthLoginResponse());
mockAPICall(server, AuthMocks.getMockAuthAccessTokenResponse());

// Storage
const userStorageMockttpControllerInstance =
new UserStorageMockttpController();

userStorageMockttpControllerInstance.setupPath('accounts', server);
userStorageMockttpControllerInstance.setupPath('networks', server);

return {
userStorageMockttpControllerInstance,
};
}

function mockAPICall(server, response) {
let requestRuleBuilder;

if (response.requestMethod === 'GET') {
requestRuleBuilder = server.forGet('/proxy');
}

if (response.requestMethod === 'POST') {
requestRuleBuilder = server.forPost('/proxy');
}

if (response.requestMethod === 'PUT') {
requestRuleBuilder = server.forPut('/proxy');
}

if (response.requestMethod === 'DELETE') {
requestRuleBuilder = server.forDelete('/proxy');
}

requestRuleBuilder
?.matching((request) => {
const url = getDecodedProxiedURL(request.url);

return url.includes(String(response.url));
})
.thenCallback(() => ({
statusCode: 200,
json: response.response,
}));
}
13 changes: 2 additions & 11 deletions e2e/specs/notifications/utils/mocks.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,24 @@
import { AuthenticationController } from '@metamask/profile-sync-controller';
import {
NotificationServicesController,
NotificationServicesPushController,
} from '@metamask/notification-services-controller';
import { UserStorageMockttpController } from './user-storage/userStorageMockttpController';
import { UserStorageMockttpController } from '../../identity/utils/user-storage/userStorageMockttpController';
import { getDecodedProxiedURL } from './helpers';

const AuthMocks = AuthenticationController.Mocks;
const NotificationMocks = NotificationServicesController.Mocks;
const PushMocks = NotificationServicesPushController.Mocks;

/**
* E2E mock setup for notification APIs (Auth, UserStorage, Notifications, Push Notifications, Profile syncing)
* E2E mock setup for notification APIs (Notifications, Push Notifications)
*
* @param server - server obj used to mock our endpoints
* @param userStorageMockttpController - optional controller to mock user storage endpoints
*/
export async function mockNotificationServices(server) {
// Auth
mockAPICall(server, AuthMocks.getMockAuthNonceResponse());
mockAPICall(server, AuthMocks.getMockAuthLoginResponse());
mockAPICall(server, AuthMocks.getMockAuthAccessTokenResponse());

// Storage
const userStorageMockttpControllerInstance =
new UserStorageMockttpController();

userStorageMockttpControllerInstance.setupPath('accounts', server);
userStorageMockttpControllerInstance.setupPath('networks', server);
userStorageMockttpControllerInstance.setupPath('notifications', server);

// Notifications
Expand Down
7 changes: 3 additions & 4 deletions e2e/tags.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const tags = {
SmokeSwaps: 'SmokeSwaps',
SmokeRest: 'SmokeRest',
smokeAssets: 'smokeAssets',
smokeNotifications: 'smokeNotifications',
smokeIdentity: 'smokeIdentity',
smokeMultiChain: 'SmokeMultiChain',
};

Expand All @@ -17,8 +17,7 @@ const SmokeConfirmations = (testName) =>
`${tags.smokeConfirmations} ${testName}`;
const SmokeSwaps = (testName) => `${tags.SmokeSwaps} ${testName}`;
const SmokeAssets = (testName) => `${tags.smokeAssets} ${testName}`;
const SmokeNotifications = (testName) =>
`${tags.smokeNotifications} ${testName}`;
const SmokeIdentity = (testName) => `${tags.smokeIdentity} ${testName}`;

const SmokeMultiChain = (testName) => `${tags.smokeMultiChain} ${testName}`;
export {
Expand All @@ -28,6 +27,6 @@ export {
SmokeConfirmations,
SmokeSwaps,
SmokeAssets,
SmokeNotifications,
SmokeIdentity,
SmokeMultiChain,
};

0 comments on commit fcb68ad

Please sign in to comment.