Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[No QA] [TS Migration] Migrate testRunner.js, UnreadIndicatorsTest.js, getIsUsingFakeTimers.js, setupAfterEnv.js, config.dev.js tests to TypeScript #37587

Merged
merged 28 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
d2c42bb
migrate config.dev.js to TypeScript
JKobrynski Feb 27, 2024
e01aa68
migrate setupAfterEnv to TypeScript
JKobrynski Feb 27, 2024
04c5067
migrate e2e server to TypeScript
JKobrynski Feb 27, 2024
a7accb5
migrate e2e server to TypeScript
JKobrynski Feb 27, 2024
4a9d9a3
start migrating testRunner to TypeScript
JKobrynski Feb 27, 2024
c229a68
add return type to promise and error
JKobrynski Feb 28, 2024
3d314f0
migrate testRunner to TypeScript
JKobrynski Feb 28, 2024
f1d7d6c
start migrating UnreadIndicatorsTest and getIsUsingFakeTimers to Type…
JKobrynski Feb 29, 2024
c7ed586
Merge branch 'main' into migrateGroup6FilesToTypeScript
JKobrynski Feb 29, 2024
cab31a1
type variables
JKobrynski Feb 29, 2024
b99ed56
remove lodashGet from UnreadIndicatorsTest
JKobrynski Feb 29, 2024
6d759f1
add emitCurrentTestState and setInitialURL to react-native module dec…
JKobrynski Feb 29, 2024
c5feb25
migrate UnreadIndicatorsTest to TypeScript
JKobrynski Feb 29, 2024
3b96a8d
migrate getIsUsingFakeTimers to TypeScript
JKobrynski Feb 29, 2024
ccf0050
cleanup the code
JKobrynski Mar 1, 2024
4e3f77f
update file extensions in docs and config
JKobrynski Mar 1, 2024
87fc66f
Merge branch 'main' into migrateGroup6FilesToTypeScript
JKobrynski Mar 4, 2024
96d86cb
apply suggested changes
JKobrynski Mar 4, 2024
2bda50d
update scripts to reference testRunner.ts
JKobrynski Mar 4, 2024
f1f2c06
apply suggested changes
JKobrynski Mar 5, 2024
2646d75
Merge branch 'main' into migrateGroup6FilesToTypeScript
JKobrynski Mar 5, 2024
b4e3503
remove unknown return types
JKobrynski Mar 5, 2024
15ef08d
Merge branch 'main' into migrateGroup6FilesToTypeScript
JKobrynski Mar 6, 2024
5bfb9f8
add type csting to testRunner.ts
JKobrynski Mar 6, 2024
5c8a661
Merge branch 'main' into migrateGroup6FilesToTypeScript
JKobrynski Mar 8, 2024
d66d9a0
Merge branch 'main' into migrateGroup6FilesToTypeScript
JKobrynski Mar 11, 2024
a2ea06c
fix typescipt error in logger
JKobrynski Mar 11, 2024
64827f8
Merge branch 'main' into migrateGroup6FilesToTypeScript
JKobrynski Mar 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/e2ePerformanceTests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ jobs:
run: npm run e2e-test-runner-build

- name: Copy e2e code into zip folder
run: cp tests/e2e/dist/index.js zip/testRunner.js
run: cp tests/e2e/dist/index.js zip/testRunner.ts

- name: Zip everything in the zip directory up
run: zip -qr App.zip ./zip
Expand Down
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module.exports = {
},
testEnvironment: 'jsdom',
setupFiles: ['<rootDir>/jest/setup.ts', './node_modules/@react-native-google-signin/google-signin/jest/build/setup.js'],
setupFilesAfterEnv: ['<rootDir>/jest/setupAfterEnv.ts', '<rootDir>/tests/perf-test/setupAfterEnv.js'],
setupFilesAfterEnv: ['<rootDir>/jest/setupAfterEnv.ts', '<rootDir>/tests/perf-test/setupAfterEnv.ts'],
cacheDirectory: '<rootDir>/.jest-cache',
moduleNameMapper: {
'\\.(lottie)$': '<rootDir>/__mocks__/fileMock.ts',
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@
"analyze-packages": "ANALYZE_BUNDLE=true webpack --config config/webpack/webpack.common.js --env envFile=.env.production",
"symbolicate:android": "npx metro-symbolicate android/app/build/generated/sourcemaps/react/release/index.android.bundle.map",
"symbolicate:ios": "npx metro-symbolicate main.jsbundle.map",
"test:e2e": "ts-node tests/e2e/testRunner.js --config ./config.local.ts",
"test:e2e:dev": "ts-node tests/e2e/testRunner.js --config ./config.dev.js",
"test:e2e": "ts-node tests/e2e/testRunner.ts --config ./config.local.ts",
"test:e2e:dev": "ts-node tests/e2e/testRunner.ts --config ./config.dev.ts",
"gh-actions-unused-styles": "./.github/scripts/findUnusedKeys.sh",
"workflow-test": "./workflow_tests/scripts/runWorkflowTests.sh",
"workflow-test:generate": "ts-node workflow_tests/utils/preGenerateTest.js",
"setup-https": "mkcert -install && mkcert -cert-file config/webpack/certificate.pem -key-file config/webpack/key.pem dev.new.expensify.com localhost 127.0.0.1",
"e2e-test-runner-build": "ncc build tests/e2e/testRunner.js -o tests/e2e/dist/"
"e2e-test-runner-build": "ncc build tests/e2e/testRunner.ts -o tests/e2e/dist/"
},
"dependencies": {
"@dotlottie/react-player": "^1.6.3",
Expand Down
19 changes: 1 addition & 18 deletions src/libs/E2E/client.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,6 @@
import Config from '../../../tests/e2e/config';
import Routes from '../../../tests/e2e/server/routes';
import type {NetworkCacheMap, TestConfig} from './types';

type TestResult = {
/** Name of the test */
name: string;

/** The branch where test were running */
branch?: string;

/** Duration in milliseconds */
duration?: number;

/** Optional, if set indicates that the test run failed and has no valid results. */
error?: string;

/** Render count */
renderCount?: number;
};
import type {NetworkCacheMap, TestConfig, TestResult} from './types';

type NativeCommandPayload = {
text: string;
Expand Down
19 changes: 18 additions & 1 deletion src/libs/E2E/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,21 @@ type TestConfig = {
[key: string]: string | {autoFocus: boolean};
};

export type {SigninParams, IsE2ETestSession, NetworkCacheMap, NetworkCacheEntry, TestConfig};
type TestResult = {
JKobrynski marked this conversation as resolved.
Show resolved Hide resolved
/** Name of the test */
name: string;

/** The branch where test were running */
branch?: string;

/** Duration in milliseconds */
duration?: number;

/** Optional, if set indicates that the test run failed and has no valid results. */
error?: string;

/** Render count */
renderCount?: number;
};

export type {SigninParams, IsE2ETestSession, NetworkCacheMap, NetworkCacheEntry, TestConfig, TestResult};
8 changes: 8 additions & 0 deletions src/types/modules/react-native.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,14 @@ declare module 'react-native' {
}
interface PressableProps extends WebPressableProps {}

interface AppStateStatic {
emitCurrentTestState: (status: string) => void;
}

interface LinkingStatic {
setInitialURL: (url: string) => void;
}

/**
* Styles
*/
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ components:
- Orchestrates the test suite.
- Runs the app with the tests on a device
- Responsible for gathering and comparing results
- Located in `e2e/testRunner.js`.
- Located in `e2e/testRunner.ts`.

- Test server:
- A nodeJS application that starts an HTTP server.
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/TestSpec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ phases:
test:
commands:
- cd zip
- node testRunner.js -- --mainAppPath app-e2eRelease.apk --deltaAppPath app-e2edeltaRelease.apk
- node testRunner.ts -- --mainAppPath app-e2eRelease.apk --deltaAppPath app-e2edeltaRelease.apk

artifacts:
- $WORKING_DIRECTORY
6 changes: 5 additions & 1 deletion tests/e2e/config.dev.js → tests/e2e/config.dev.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import type {Config} from './config.local';

const packageName = 'com.expensify.chat.dev';
const appPath = './android/app/build/outputs/apk/development/debug/app-development-debug.apk';

export default {
const config: Config = {
MAIN_APP_PACKAGE: packageName,
DELTA_APP_PACKAGE: packageName,
MAIN_APP_PATH: appPath,
DELTA_APP_PATH: appPath,
RUNS: 8,
BOOT_COOL_DOWN: 5 * 1000,
};

export default config;
1 change: 1 addition & 0 deletions tests/e2e/config.local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ const config: Config = {
};

export default config;
export type {Config};
4 changes: 2 additions & 2 deletions tests/e2e/server/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {createServer} from 'http';
import type {IncomingMessage, ServerResponse} from 'http';
import {createServer} from 'http';
import type {NativeCommand, TestResult} from '@libs/E2E/client';
import type {NetworkCacheMap, TestConfig} from '@libs/E2E/types';
import config from '../config';
Expand Down Expand Up @@ -166,7 +166,7 @@ const createServerInstance = (): ServerInstance => {
return;
}

const cachedData = networkCache[appInstanceId] || {};
const cachedData = networkCache[appInstanceId] ?? {};
res.end(JSON.stringify(cachedData));
});

Expand Down
57 changes: 30 additions & 27 deletions tests/e2e/testRunner.js → tests/e2e/testRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
/* eslint-disable @lwc/lwc/no-async-await,no-restricted-syntax,no-await-in-loop */
import {execSync} from 'child_process';
import fs from 'fs';
import _ from 'underscore';
import type {TestConfig} from '@libs/E2E/types';
import compare from './compare/compare';
import defaultConfig from './config';
import createServerInstance from './server';
Expand All @@ -28,9 +28,11 @@ import * as Logger from './utils/logger';
import sleep from './utils/sleep';
import withFailTimeout from './utils/withFailTimeout';

type Result = Record<string, number[]>;

// VARIABLE CONFIGURATION
const args = process.argv.slice(2);
const getArg = (argName) => {
const getArg = (argName: string): string | undefined => {
const argIndex = args.indexOf(argName);
if (argIndex === -1) {
return undefined;
Expand All @@ -39,13 +41,13 @@ const getArg = (argName) => {
};

let config = defaultConfig;
const setConfigPath = (configPathParam) => {
const setConfigPath = (configPathParam: string | undefined) => {
let configPath = configPathParam;
if (!configPath.startsWith('.')) {
if (!configPath?.startsWith('.')) {
configPath = `./${configPath}`;
}
const customConfig = require(configPath).default;
config = _.extend(defaultConfig, customConfig);
config = Object.assign(defaultConfig, customConfig);
};

if (args.includes('--config')) {
Expand All @@ -54,8 +56,8 @@ if (args.includes('--config')) {
}

// Important: set app path only after correct config file has been loaded
const mainAppPath = getArg('--mainAppPath') || config.MAIN_APP_PATH;
const deltaAppPath = getArg('--deltaAppPath') || config.DELTA_APP_PATH;
const mainAppPath = getArg('--mainAppPath') ?? config.MAIN_APP_PATH;
const deltaAppPath = getArg('--deltaAppPath') ?? config.DELTA_APP_PATH;
// Check if files exists:
if (!fs.existsSync(mainAppPath)) {
throw new Error(`Main app path does not exist: ${mainAppPath}`);
Expand All @@ -76,8 +78,7 @@ try {
}

// START OF TEST CODE

const runTests = async () => {
const runTests = async (): Promise<void> => {
Logger.info('Installing apps and reversing port');
await installApp(config.MAIN_APP_PACKAGE, mainAppPath);
await installApp(config.DELTA_APP_PACKAGE, deltaAppPath);
Expand All @@ -88,36 +89,38 @@ const runTests = async () => {
await server.start();

// Create a dict in which we will store the run durations for all tests
const results = {};
const results: Record<string, Result> = {};

// Collect results while tests are being executed
server.addTestResultListener((testResult) => {
if (testResult.error != null) {
if (testResult?.error != null) {
throw new Error(`Test '${testResult.name}' failed with error: ${testResult.error}`);
}
let result = 0;

if ('duration' in testResult) {
if (testResult?.duration !== undefined) {
if (testResult.duration < 0) {
return;
}
result = testResult.duration;
}
if ('renderCount' in testResult) {
if (testResult?.renderCount !== undefined) {
result = testResult.renderCount;
}

Logger.log(`[LISTENER] Test '${testResult.name}' on '${testResult.branch}' measured ${result}`);
Logger.log(`[LISTENER] Test '${testResult?.name}' on '${testResult?.branch}' measured ${result}`);

if (!results[testResult.branch]) {
if (testResult?.branch && !results[testResult.branch]) {
results[testResult.branch] = {};
}

results[testResult.branch][testResult.name] = (results[testResult.branch][testResult.name] || []).concat(result);
if (testResult?.branch && testResult?.name) {
results[testResult.branch][testResult.name] = (results[testResult.branch][testResult.name] ?? []).concat(result);
}
});

// Function to run a single test iteration
async function runTestIteration(appPackage, iterationText, launchArgs) {
async function runTestIteration(appPackage: string, iterationText: string, launchArgs: Record<string, boolean> = {}): Promise<void> {
Logger.info(iterationText);

// Making sure the app is really killed (e.g. if a prior test run crashed)
Expand All @@ -128,10 +131,9 @@ const runTests = async () => {
await launchApp('android', appPackage, config.ACTIVITY_PATH, launchArgs);

await withFailTimeout(
new Promise((resolve) => {
const cleanup = server.addTestDoneListener(() => {
new Promise<void>((resolve) => {
server.addTestDoneListener(() => {
Logger.success(iterationText);
cleanup();
resolve();
});
}),
Expand All @@ -143,9 +145,9 @@ const runTests = async () => {
}

// Run the tests
const tests = _.values(config.TESTS_CONFIG);
const tests = Object.keys(config.TESTS_CONFIG);
for (let testIndex = 0; testIndex < tests.length; testIndex++) {
const test = _.values(config.TESTS_CONFIG)[testIndex];
const test = Object.values(config.TESTS_CONFIG)[testIndex];

// check if we want to skip the test
if (args.includes('--includes')) {
Expand All @@ -164,7 +166,7 @@ const runTests = async () => {
Logger.info(`Cooling down for ${config.BOOT_COOL_DOWN / 1000}s`);
await sleep(config.BOOT_COOL_DOWN);

server.setTestConfig(test);
server.setTestConfig(test as TestConfig);

const warmupText = `Warmup for test '${test.name}' [${testIndex + 1}/${tests.length}]`;

Expand All @@ -182,7 +184,7 @@ const runTests = async () => {

// We run each test multiple time to average out the results
for (let testIteration = 0; testIteration < config.RUNS; testIteration++) {
const onError = (e) => {
const onError = (e: Error) => {
errorCountRef.errorCount += 1;
if (testIteration === 0 || errorCountRef.errorCount === errorCountRef.allowedExceptions) {
Logger.error("There was an error running the test and we've reached the maximum number of allowed exceptions. Stopping the test run.");
Expand All @@ -191,6 +193,7 @@ const runTests = async () => {
// maximum number of allowed exceptions, we should stop the test run.
throw e;
}
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
Logger.warn(`There was an error running the test. Continuing the test run. Error: ${e}`);
JKobrynski marked this conversation as resolved.
Show resolved Hide resolved
};

Expand All @@ -208,7 +211,7 @@ const runTests = async () => {
// Run the test on the delta app:
await runTestIteration(config.DELTA_APP_PACKAGE, deltaIterationText, launchArgs);
} catch (e) {
onError(e);
onError(e as Error);
}
}
}
Expand All @@ -228,7 +231,7 @@ const run = async () => {

process.exit(0);
} catch (e) {
Logger.info('\n\nE2E test suite failed due to error:', e, '\nPrinting full logs:\n\n');
Logger.info('\n\nE2E test suite failed due to error:', e as string, '\nPrinting full logs:\n\n');

// Write logcat, meminfo, emulator info to file as well:
execSync(`adb logcat -d > ${config.OUTPUT_DIR}/logcat.txt`);
Expand All @@ -237,7 +240,7 @@ const run = async () => {

execSync(`cat ${config.LOG_FILE}`);
try {
execSync(`cat ~/.android/avd/${process.env.AVD_NAME || 'test'}.avd/config.ini > ${config.OUTPUT_DIR}/emulator-config.ini`);
execSync(`cat ~/.android/avd/${process.env.AVD_NAME ?? 'test'}.avd/config.ini > ${config.OUTPUT_DIR}/emulator-config.ini`);
} catch (ignoredError) {
// the error is ignored, as the file might not exist if the test
// run wasn't started with an emulator
Expand Down
File renamed without changes.
Loading
Loading