Skip to content

Commit

Permalink
Merge pull request #28896 from VickyStash/ts-migration/e2e-lib
Browse files Browse the repository at this point in the history
[No QA] [TS migration] Migrate 'E2E' lib to TypeScript
  • Loading branch information
madmax330 authored Nov 14, 2023
2 parents 358c3bf + d790b48 commit d82dc7a
Show file tree
Hide file tree
Showing 38 changed files with 321 additions and 121 deletions.
2 changes: 1 addition & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ package-lock.json
*.scss
*.md
# We need to modify the import here specifically, hence we disable prettier to get rid of the sorted imports
src/libs/E2E/reactNativeLaunchingTest.js
src/libs/E2E/reactNativeLaunchingTest.ts
6 changes: 3 additions & 3 deletions fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ opt_out_usage

platform :android do
desc "Generate a new local APK for e2e testing"

lane :build_e2e do
ENV["ENVFILE"]="tests/e2e/.env.e2e"
ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.js"
ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.ts"
ENV["E2E_TESTING"]="true"

gradle(
Expand All @@ -31,7 +31,7 @@ platform :android do

lane :build_e2edelta do
ENV["ENVFILE"]="tests/e2e/.env.e2edelta"
ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.js"
ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.ts"
ENV["E2E_TESTING"]="true"

gradle(
Expand Down
2 changes: 1 addition & 1 deletion metro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const config = {
const resolution = context.resolveRequest(context, moduleName, platform);
if (isE2ETesting && moduleName.includes('/API')) {
const originalPath = resolution.filePath;
const mockPath = originalPath.replace('src/libs/API.ts', 'src/libs/E2E/API.mock.js').replace('/src/libs/API.js/', 'src/libs/E2E/API.mock.js');
const mockPath = originalPath.replace('src/libs/API.ts', 'src/libs/E2E/API.mock.ts').replace('/src/libs/API.ts/', 'src/libs/E2E/API.mock.ts');
// eslint-disable-next-line no-console
console.log('⚠️⚠️⚠️⚠️ Replacing resolution path', originalPath, ' => ', mockPath);

Expand Down
70 changes: 70 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,76 @@ const CONST = {
CUSTOM_STATUS: 'customStatus',
NEW_DOT_TAGS: 'newDotTags',
NEW_DOT_SAML: 'newDotSAML',
PDF_META_STORE: 'pdfMetaStore',
REPORT_ACTION_CONTEXT_MENU: 'reportActionContextMenu',
SUBMIT_POLICY: 'submitPolicy',
ATTENDEES: 'attendees',
AUTO_EXPORT: 'autoExport',
AUTO_EXPORT_INTACCT: 'autoExportIntacct',
AUTO_EXPORT_QBO: 'autoExportQbo',
AUTO_EXPORT_XERO: 'autoExportXero',
AUTO_JOIN_POLICY: 'autoJoinPolicy',
AUTOMATED_TAX_EXEMPTION: 'automatedTaxExemption',
BILL_PAY: 'billPay',
CATEGORY_DEFAULT_TAX: 'categoryDefaultTax',
COLLECTABLE_DEPOSIT_ACCOUNTS: 'collectableDepositAccounts',
CONCIERGE_TRAVEL: 'conciergeTravel',
CONNECTED_CARDS: 'connectedCards',
DISCREPANCY: 'discrepancy',
DOMAIN_CONTACT_BILLING: 'domainContactBilling',
DOMAIN_TWO_FACTOR_AUTH: 'domainTwoFactorAuth',
DUPLICATE_DETECTION: 'duplicateDetection',
EMAIL_SUPPRESSION_BETA: 'emailSuppressionBeta',
EXPENSES_V2: 'expensesV2',
EXPENSIFY_CARD: 'expensifyCard',
EXPENSIFY_CARD_INTACCT_RECONCILIATION: 'expensifyCardIntacctReconciliation',
EXPENSIFY_CARD_NETSUITE_RECONCILIATION: 'expensifyCardNetSuiteReconciliation',
EXPENSIFY_CARD_QBO_RECONCILIATION: 'expensifyCardQBOReconciliation',
EXPENSIFY_CARD_RAPID_INCREASE_FRAUD: 'expensifyCardRapidIncreaseFraud',
EXPENSIFY_CARD_XERO_RECONCILIATION: 'expensifyCardXeroReconciliation',
EXPENSIFY_ORG: 'expensifyOrg',
FIX_VIOLATION_PUSH_NOTIFICATION: 'fixViolationPushNotification',
FREE_PLAN_FULL_LAUNCH: 'freePlanFullLaunch',
FREE_PLAN_SOFT_LAUNCH: 'freePlanSoftLaunch',
GUSTO: 'gusto',
INBOX_CACHE: 'inboxCache',
INBOX_HIDDEN_TASKS: 'inboxHiddenTasks',
INDIRECT_INTEGRATION_SETUP: 'indirectIntegrationSetup',
IOU: 'IOU',
JOIN_POLICY: 'joinPolicy',
LOAD_POLICY_ASYNC: 'loadPolicyAsync',
MAP_RECEIPT: 'mapReceipt',
MERGE_API: 'mergeAPI',
MOBILE_REALTIME_REPORT_COMMENTS: 'mobileRealtimeReportComments',
MOBILE_SECURE_RECEIPTS: 'mobileSecureReceipts',
MONTHLY_SETTLEMENT: 'monthlySettlement',
NAMES_AND_AVATARS: 'namesAndAvatars',
NATIVE_CHAT: 'nativeChat',
NEW_PRICING: 'newPricing',
NEWSLETTER_THREE: 'newsletterThree',
NEXT_STEPS: 'nextSteps',
OPEN_FACE_HAMBURGER: 'openFaceHamburger',
PER_DIEM: 'perDiem',
PER_DIEM_INTERNATIONAL: 'perDiemInternational',
PRICING_COPY_CHANGES: 'pricingCopyChanges',
QBO_INVOICES: 'qboInvoices',
QUICKBOOKS_DESKTOP_V2: 'quickbooksDesktopV2',
REALTIME_REPORT_COMMENTS: 'realtimeReportComments',
S2W_ANNOUNCEMENT: 's2wAnnouncement',
SCHEDULED_AUTO_REPORTING: 'scheduledAutoReporting',
SECURE_RECEIPTS: 'secureReceipts',
SECURE_RECEIPTS_REPORTS: 'secureReceiptsReports',
SELF_SERVICE_HARD_LAUNCH: 'selfServiceHardLaunch',
SEND_MONEY: 'sendMoney',
SMART_SCAN_USER_DISPUTES: 'smartScanUserDisputes',
SMS_SIGN_UP: 'smsSignUp',
STRIPE_CONNECT: 'stripeConnect',
SUMMARY_EMAIL: 'summaryEmail',
SWIPE_TO_WIN: 'swipeToWin',
TAX_FOR_MILEAGE: 'taxForMileage',
TWO_FACTOR_AUTH: 'twoFactorAuth',
VENMO_INTEGRATION: 'venmoIntegration',
ZENEFITS_INTEGRATION: 'zenefitsIntegration',
VIOLATIONS: 'violations',
},
BUTTON_STATES: {
Expand Down
2 changes: 1 addition & 1 deletion src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ type OnyxValues = {
[ONYXKEYS.COUNTRY_CODE]: number;
[ONYXKEYS.COUNTRY]: string;
[ONYXKEYS.USER]: OnyxTypes.User;
[ONYXKEYS.LOGIN_LIST]: OnyxTypes.Login;
[ONYXKEYS.LOGIN_LIST]: Record<string, OnyxTypes.Login>;
[ONYXKEYS.SESSION]: OnyxTypes.Session;
[ONYXKEYS.BETAS]: OnyxTypes.Beta[];
[ONYXKEYS.NVP_PRIORITY_MODE]: ValueOf<typeof CONST.PRIORITY_MODE>;
Expand Down
41 changes: 19 additions & 22 deletions src/libs/E2E/API.mock.js → src/libs/E2E/API.mock.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
/* eslint-disable rulesdir/no-api-in-views */
import Onyx from 'react-native-onyx';
import _ from 'underscore';
import Log from '@libs/Log';
import mockAuthenticatePusher from './apiMocks/authenticatePusher';
import Response from '@src/types/onyx/Response';
// mock functions
import mockAuthenticatePusher from './apiMocks/authenticatePusher';
import mockBeginSignin from './apiMocks/beginSignin';
import mockOpenApp from './apiMocks/openApp';
import mockOpenReport from './apiMocks/openReport';
import mockReadNewestAction from './apiMocks/readNewestAction';
import mockSigninUser from './apiMocks/signinUser';

type ApiCommandParameters = Record<string, unknown>;

type Mocks = Record<string, (params: ApiCommandParameters) => Response>;

/**
* A dictionary which has the name of a API command as key, and a function which
* receives the api command parameters as value and is expected to return a response
* object.
*/
const mocks = {
const mocks: Mocks = {
BeginSignIn: mockBeginSignin,
SigninUser: mockSigninUser,
OpenApp: mockOpenApp,
Expand All @@ -26,14 +29,14 @@ const mocks = {
ReadNewestAction: mockReadNewestAction,
};

function mockCall(command, apiCommandParameters, tag) {
const mockResponse = mocks[command] && mocks[command](apiCommandParameters);
function mockCall(command: string, apiCommandParameters: ApiCommandParameters, tag: string): Promise<void> | Promise<Response> | undefined {
const mockResponse = mocks[command]?.(apiCommandParameters);
if (!mockResponse) {
Log.warn(`[${tag}] for command ${command} is not mocked yet! ⚠️`);
return;
}

if (_.isArray(mockResponse.onyxData)) {
if (Array.isArray(mockResponse.onyxData)) {
return Onyx.update(mockResponse.onyxData);
}

Expand All @@ -44,12 +47,10 @@ function mockCall(command, apiCommandParameters, tag) {
* All calls to API.write() will be persisted to disk as JSON with the params, successData, and failureData.
* This is so that if the network is unavailable or the app is closed, we can send the WRITE request later.
*
* @param {String} command - Name of API command to call.
* @param {Object} apiCommandParameters - Parameters to send to the API.
*
* @returns {Promise}
* @param command - Name of API command to call.
* @param apiCommandParameters - Parameters to send to the API.
*/
function write(command, apiCommandParameters = {}) {
function write(command: string, apiCommandParameters: ApiCommandParameters = {}): Promise<void> | Promise<Response> | undefined {
return mockCall(command, apiCommandParameters, 'API.write');
}

Expand All @@ -61,24 +62,20 @@ function write(command, apiCommandParameters = {}) {
* Using this method is discouraged and will throw an ESLint error. Use it sparingly and only when all other alternatives have been exhausted.
* It is best to discuss it in Slack anytime you are tempted to use this method.
*
* @param {String} command - Name of API command to call.
* @param {Object} apiCommandParameters - Parameters to send to the API.
*
* @returns {Promise}
* @param command - Name of API command to call.
* @param apiCommandParameters - Parameters to send to the API.
*/
function makeRequestWithSideEffects(command, apiCommandParameters = {}) {
function makeRequestWithSideEffects(command: string, apiCommandParameters: ApiCommandParameters = {}): Promise<void> | Promise<Response> | undefined {
return mockCall(command, apiCommandParameters, 'API.makeRequestWithSideEffects');
}

/**
* Requests made with this method are not be persisted to disk. If there is no network connectivity, the request is ignored and discarded.
*
* @param {String} command - Name of API command to call.
* @param {Object} apiCommandParameters - Parameters to send to the API.
*
* @returns {Promise}
* @param command - Name of API command to call.
* @param apiCommandParameters - Parameters to send to the API.
*/
function read(command, apiCommandParameters) {
function read(command: string, apiCommandParameters: ApiCommandParameters): Promise<void> | Promise<Response> | undefined {
return mockCall(command, apiCommandParameters, 'API.read');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,16 @@ import ONYXKEYS from '@src/ONYXKEYS';
* If the user is already logged in the function will simply
* resolve.
*
* @param {String} email
* @param {String} password
* @return {Promise<boolean>} Resolved true when the user was actually signed in. Returns false if the user was already logged in.
* @return Resolved true when the user was actually signed in. Returns false if the user was already logged in.
*/
export default function (email = '[email protected]', password = 'Password123') {
const waitForBeginSignInToFinish = () =>
export default function (email = '[email protected]', password = 'Password123'): Promise<boolean> {
const waitForBeginSignInToFinish = (): Promise<void> =>
new Promise((resolve) => {
const id = Onyx.connect({
key: ONYXKEYS.CREDENTIALS,
callback: (credentials) => {
// beginSignUp writes to credentials.login once the API call is complete
if (!credentials.login) {
if (!credentials?.login) {
return;
}

Expand All @@ -36,7 +34,7 @@ export default function (email = '[email protected]', password = 'Password123') {
const connectionId = Onyx.connect({
key: ONYXKEYS.SESSION,
callback: (session) => {
if (session.authToken == null || session.authToken.length === 0) {
if (session?.authToken == null || session.authToken.length === 0) {
neededLogin = true;

// authenticate with a predefined user
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Keyboard} from 'react-native';

export default function waitForKeyboard() {
export default function waitForKeyboard(): Promise<void> {
return new Promise((resolve) => {
function checkKeyboard() {
if (Keyboard.isVisible()) {
Expand Down
6 changes: 0 additions & 6 deletions src/libs/E2E/apiMocks/authenticatePusher.js

This file was deleted.

11 changes: 11 additions & 0 deletions src/libs/E2E/apiMocks/authenticatePusher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Response from '@src/types/onyx/Response';

const authenticatePusher = (): Response => ({
auth: 'auth',
// eslint-disable-next-line @typescript-eslint/naming-convention
shared_secret: 'secret',
jsonCode: 200,
requestID: '783ef7fc3991969a-SJC',
});

export default authenticatePusher;
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export default ({email}) => ({
import {SigninParams} from '@libs/E2E/types';
import Response from '@src/types/onyx/Response';

const beginSignin = ({email}: SigninParams): Response => ({
onyxData: [
{
onyxMethod: 'merge',
Expand All @@ -23,3 +26,5 @@ export default ({email}) => ({
jsonCode: 200,
requestID: '783e54ef4b38cff5-SJC',
});

export default beginSignin;
Loading

0 comments on commit d82dc7a

Please sign in to comment.