From 0bcf5eae6674fe1dc06b26bc860d0e79b797cf10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 24 Oct 2023 11:23:28 +0200 Subject: [PATCH 01/30] wip: adding adb commands --- .../nativeCommands/NativeCommandsAction.js | 16 ++++++++++++++++ tests/e2e/nativeCommands/adbTypeText.js | 10 ++++++++++ tests/e2e/nativeCommands/index.js | 19 +++++++++++++++++++ tests/e2e/server/index.js | 15 +++++++++++++++ tests/e2e/server/routes.js | 3 +++ 5 files changed, 63 insertions(+) create mode 100644 tests/e2e/nativeCommands/NativeCommandsAction.js create mode 100644 tests/e2e/nativeCommands/adbTypeText.js create mode 100644 tests/e2e/nativeCommands/index.js diff --git a/tests/e2e/nativeCommands/NativeCommandsAction.js b/tests/e2e/nativeCommands/NativeCommandsAction.js new file mode 100644 index 000000000000..ce6b38079527 --- /dev/null +++ b/tests/e2e/nativeCommands/NativeCommandsAction.js @@ -0,0 +1,16 @@ +const NativeCommandsAction = { + scroll: 'scroll', + type: 'type', +}; + +const makeTypeTextCommand = (text) => ({ + command: NativeCommandsAction.type, + payload: { + text, + }, +}); + +module.exports = { + NativeCommandsAction, + makeTypeTextCommand, +}; diff --git a/tests/e2e/nativeCommands/adbTypeText.js b/tests/e2e/nativeCommands/adbTypeText.js new file mode 100644 index 000000000000..cbaa9f4434a2 --- /dev/null +++ b/tests/e2e/nativeCommands/adbTypeText.js @@ -0,0 +1,10 @@ +const execAsync = require('../utils/execAsync'); +const Logger = require('../utils/logger'); + +const adbTypeText = async (text) => { + Logger.log(`📝 Typing text: ${text}`); + execAsync(`adb shell input text "${text}"`); + return true; +}; + +module.exports = adbTypeText; diff --git a/tests/e2e/nativeCommands/index.js b/tests/e2e/nativeCommands/index.js new file mode 100644 index 000000000000..7452dce3067c --- /dev/null +++ b/tests/e2e/nativeCommands/index.js @@ -0,0 +1,19 @@ +const adbTypeText = require('./adbTypeText'); +const {NativeCommandsAction} = require('./NativeCommandsAction'); + +const executeFromPayload = (actionName, payload) => { + switch (actionName) { + case NativeCommandsAction.scroll: + throw new Error('Not implemented yet'); + case NativeCommandsAction.type: + return adbTypeText(payload.text); + default: + throw new Error(`Unknown action: ${actionName}`); + } +}; + +module.exports = { + NativeCommandsAction, + executeFromPayload, + adbTypeText, +}; diff --git a/tests/e2e/server/index.js b/tests/e2e/server/index.js index 3910ef43f798..94b4e8abec09 100644 --- a/tests/e2e/server/index.js +++ b/tests/e2e/server/index.js @@ -2,6 +2,7 @@ const {createServer} = require('http'); const Routes = require('./routes'); const Logger = require('../utils/logger'); const {SERVER_PORT} = require('../config'); +const {executeFromPayload} = require('../nativeCommands'); const PORT = process.env.PORT || SERVER_PORT; @@ -125,6 +126,20 @@ const createServerInstance = () => { return res.end('ok'); } + case Routes.testNativeCommand: { + getPostJSONRequestData(req, res).then((data) => { + const status = executeFromPayload(data.actionName, data.payload); + if (status) { + res.end('ok'); + } else { + res.statusCode = 500; + res.end('Error executing command'); + } + }); + + break; + } + default: res.statusCode = 404; res.end('Page not found!'); diff --git a/tests/e2e/server/routes.js b/tests/e2e/server/routes.js index 5aac2fef4dc2..84fc2f89fd9b 100644 --- a/tests/e2e/server/routes.js +++ b/tests/e2e/server/routes.js @@ -7,4 +7,7 @@ module.exports = { // When the app is done running a test it calls this endpoint testDone: '/test_done', + + // Commands to execute from the host machine (there are pre-defined types like scroll or type) + testNativeCommand: '/test_native_command', }; From 947b43ec83fa411e59df5ddfc91842c5bc8e98e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 24 Oct 2023 13:20:22 +0200 Subject: [PATCH 02/30] remove branch args --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 02dbf576764d..c1b4deff017c 100644 --- a/package.json +++ b/package.json @@ -49,8 +49,8 @@ "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:main": "node tests/e2e/testRunner.js --development --branch main --skipCheckout", - "test:e2e:delta": "node tests/e2e/testRunner.js --development --branch main --label delta --skipCheckout", + "test:e2e:main": "node tests/e2e/testRunner.js --development --skipCheckout", + "test:e2e:delta": "node tests/e2e/testRunner.js --development --label delta --skipCheckout --skipInstallDeps", "test:e2e:compare": "node tests/e2e/merge.js", "gh-actions-unused-styles": "./.github/scripts/findUnusedKeys.sh", "workflow-test": "./workflow_tests/scripts/runWorkflowTests.sh", From 51d2ffcd36240526692a9adf2a5b37fedb0ed611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 24 Oct 2023 13:26:43 +0200 Subject: [PATCH 03/30] add package scripts to help run in dev mode --- package.json | 1 + tests/e2e/ADDING_TESTS.md | 2 +- tests/e2e/config.dev.js | 5 +++++ tests/e2e/config.local.js | 2 +- 4 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 tests/e2e/config.dev.js diff --git a/package.json b/package.json index c1b4deff017c..f2b2ffef70c3 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "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:dev": "node tests/e2e/testRunner.js --development --skipCheckout --config ./config.dev.js --buildMode skip --skipInstallDeps", "test:e2e:main": "node tests/e2e/testRunner.js --development --skipCheckout", "test:e2e:delta": "node tests/e2e/testRunner.js --development --label delta --skipCheckout --skipInstallDeps", "test:e2e:compare": "node tests/e2e/merge.js", diff --git a/tests/e2e/ADDING_TESTS.md b/tests/e2e/ADDING_TESTS.md index dcd08aeee441..ef7f6cf01a39 100644 --- a/tests/e2e/ADDING_TESTS.md +++ b/tests/e2e/ADDING_TESTS.md @@ -35,7 +35,7 @@ CAPTURE_METRICS=TRUE E2E_Testing=true npm start -- --reset-cache Then we can execute our test with: ``` -npm run test:e2e -- --development --skipInstallDeps --buildMode skip --includes "My new test name" +npm run test:e2e:dev -- --includes "My new test name" ``` > - `--development` will run the tests with a local config, which will run the tests with fewer iterations diff --git a/tests/e2e/config.dev.js b/tests/e2e/config.dev.js new file mode 100644 index 000000000000..46191ebdee48 --- /dev/null +++ b/tests/e2e/config.dev.js @@ -0,0 +1,5 @@ +module.exports = { + APP_PACKAGE: 'com.expensify.chat.dev', + APP_PATH: './android/app/build/outputs/apk/development/debug/app-development-debug.apk', + RUNS: 8, +}; diff --git a/tests/e2e/config.local.js b/tests/e2e/config.local.js index 15b091d8ba70..8cdfc50ac625 100644 --- a/tests/e2e/config.local.js +++ b/tests/e2e/config.local.js @@ -1,5 +1,5 @@ module.exports = { APP_PACKAGE: 'com.expensify.chat.adhoc', APP_PATH: './android/app/build/outputs/apk/e2e/release/app-e2e-release.apk', - RUNS: 8, + RUNS: 4, }; From 4347739219909a59c900cc5b7adae2dcc2df9e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 24 Oct 2023 13:28:29 +0200 Subject: [PATCH 04/30] fix docs --- tests/e2e/ADDING_TESTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/ADDING_TESTS.md b/tests/e2e/ADDING_TESTS.md index ef7f6cf01a39..bbebd4d76a33 100644 --- a/tests/e2e/ADDING_TESTS.md +++ b/tests/e2e/ADDING_TESTS.md @@ -15,7 +15,7 @@ I recommend doing the following. 1. Rename `./index.js` to `./appIndex.js` 2. Create a new `./index.js` with the following content: ```js -requrire("./src/libs/E2E/reactNativeLaunchingTest.js"); +require('./src/libs/E2E/reactNativeLaunchingTest'); ``` 3. In `./src/libs/E2E/reactNativeLaunchingTest.js` change the main app import to the new `./appIndex.js` file: ```diff From 951c92a387ed1fed3e7fa865057f877f3b972bf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 24 Oct 2023 15:58:55 +0200 Subject: [PATCH 05/30] update documentation --- tests/e2e/ADDING_TESTS.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/tests/e2e/ADDING_TESTS.md b/tests/e2e/ADDING_TESTS.md index bbebd4d76a33..5bede6ada72a 100644 --- a/tests/e2e/ADDING_TESTS.md +++ b/tests/e2e/ADDING_TESTS.md @@ -12,12 +12,20 @@ I recommend doing the following. > [!NOTE] > All of the steps can be executed at once by running XXX (todo) -1. Rename `./index.js` to `./appIndex.js` -2. Create a new `./index.js` with the following content: +1. We need to compile a android development app version that has capturing metrics enabled: +```bash +# Make sure that your .env file is the one we need for e2e testing: +cp ./tests/e2e/.env.e2e .env + +# Build the android app like you normally would with +npm run android +``` +2. Rename `./index.js` to `./appIndex.js` +3. Create a new `./index.js` with the following content: ```js require('./src/libs/E2E/reactNativeLaunchingTest'); ``` -3. In `./src/libs/E2E/reactNativeLaunchingTest.js` change the main app import to the new `./appIndex.js` file: +4. In `./src/libs/E2E/reactNativeLaunchingTest.js` change the main app import to the new `./appIndex.js` file: ```diff - import '../../../index'; + import '../../../appIndex'; @@ -29,7 +37,7 @@ require('./src/libs/E2E/reactNativeLaunchingTest'); Now you can start the metro bundler in e2e mode with: ``` -CAPTURE_METRICS=TRUE E2E_Testing=true npm start -- --reset-cache +CAPTURE_METRICS=true E2E_TESTING=true npm start -- --reset-cache ``` Then we can execute our test with: @@ -38,11 +46,7 @@ Then we can execute our test with: npm run test:e2e:dev -- --includes "My new test name" ``` -> - `--development` will run the tests with a local config, which will run the tests with fewer iterations -> - `--skipInstallDeps` will skip the `npm install` step, which you probably don't need -> - `--buildMode skip` will skip rebuilding the app, and just run the existing app -> - `--includes "MyTestName"` will only run the test with the name "MyTestName" - +> - `--includes "MyTestName"` will only run the test with the name "MyTestName", but is optional ## Creating a new test From e16b21866ce5085d1fca13b33989c93efd067b6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 24 Oct 2023 15:59:33 +0200 Subject: [PATCH 06/30] doc: improve wording --- tests/e2e/ADDING_TESTS.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/e2e/ADDING_TESTS.md b/tests/e2e/ADDING_TESTS.md index 5bede6ada72a..73d474882269 100644 --- a/tests/e2e/ADDING_TESTS.md +++ b/tests/e2e/ADDING_TESTS.md @@ -2,10 +2,10 @@ ## Running your new test in development mode -Typically you'd run all the tests with `npm run test:e2e` on your machine, -this will run the tests with some local settings, however that is not -optimal when you add a new test for which you want to quickly test if it works, as it -still runs the release version of the app. +Typically you'd run all the tests with `npm run test:e2e` on your machine. +This will run the tests with some local settings, however that is not +optimal when you add a new test for which you want to quickly test if it works, as the prior command +still runs the release version of the app, which is hard to debug. I recommend doing the following. From 37622920e5cb84dc8b16d87e1bd37b30be3e07b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 24 Oct 2023 15:59:43 +0200 Subject: [PATCH 07/30] remove note --- tests/e2e/ADDING_TESTS.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/e2e/ADDING_TESTS.md b/tests/e2e/ADDING_TESTS.md index 73d474882269..ac43e61f60ed 100644 --- a/tests/e2e/ADDING_TESTS.md +++ b/tests/e2e/ADDING_TESTS.md @@ -9,9 +9,6 @@ still runs the release version of the app, which is hard to debug. I recommend doing the following. -> [!NOTE] -> All of the steps can be executed at once by running XXX (todo) - 1. We need to compile a android development app version that has capturing metrics enabled: ```bash # Make sure that your .env file is the one we need for e2e testing: From 8351917696c610adf0daa499d00596d1c0bc4c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Wed, 25 Oct 2023 08:40:48 +0200 Subject: [PATCH 08/30] wip adding test --- src/libs/E2E/tests/chatTypingTest.e2e.js | 26 ++++++++++++++++++++++++ tests/e2e/config.js | 1 + 2 files changed, 27 insertions(+) create mode 100644 src/libs/E2E/tests/chatTypingTest.e2e.js diff --git a/src/libs/E2E/tests/chatTypingTest.e2e.js b/src/libs/E2E/tests/chatTypingTest.e2e.js new file mode 100644 index 000000000000..50b003e966d5 --- /dev/null +++ b/src/libs/E2E/tests/chatTypingTest.e2e.js @@ -0,0 +1,26 @@ +import E2ELogin from '../actions/e2eLogin'; +import Performance from '../../Performance'; +import E2EClient from '../client'; + +const test = () => { + // check for login (if already logged in the action will simply resolve) + console.debug('[E2E] Logging in for typing'); + + E2ELogin().then((neededLogin) => { + if (neededLogin) { + // we don't want to submit the first login to the results + return E2EClient.submitTestDone(); + } + + console.debug('[E2E] Logged in, getting typing metrics and submitting them…'); + + Performance.subscribeToMeasurements((entry) => { + if (entry.name === CONST.TIMING.SIDEBAR_LOADED) { + console.debug(`[E2E] Sidebar loaded, navigating to a report…`); + Navigation.navigate(ROUTES.SEARCH); + } + }); + }); +}; + +export default test; diff --git a/tests/e2e/config.js b/tests/e2e/config.js index 3b1856ab8ad8..270509e3df20 100644 --- a/tests/e2e/config.js +++ b/tests/e2e/config.js @@ -9,6 +9,7 @@ const OUTPUT_DIR = process.env.WORKING_DIRECTORY || './tests/e2e/results'; const TEST_NAMES = { AppStartTime: 'App start time', OpenSearchPage: 'Open search page TTI', + ReportTyping: 'Report typing', }; /** From abeb8f18cbc7f2be22b9fc8981cecd866dc48648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Wed, 25 Oct 2023 08:44:51 +0200 Subject: [PATCH 09/30] add missing config entry --- tests/e2e/config.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/e2e/config.js b/tests/e2e/config.js index 270509e3df20..34cd13a8f6db 100644 --- a/tests/e2e/config.js +++ b/tests/e2e/config.js @@ -64,5 +64,8 @@ module.exports = { [TEST_NAMES.OpenSearchPage]: { name: TEST_NAMES.OpenSearchPage, }, + [TEST_NAMES.ReportTyping]: { + name: TEST_NAMES.ReportTyping, + }, }, }; From dad39571ddef69b6316425918242b98dc454f3e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Wed, 25 Oct 2023 09:13:18 +0200 Subject: [PATCH 10/30] fix api mock not returning data when none onyx request --- src/libs/E2E/API.mock.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libs/E2E/API.mock.js b/src/libs/E2E/API.mock.js index 47f445f72222..ba85cd19aac3 100644 --- a/src/libs/E2E/API.mock.js +++ b/src/libs/E2E/API.mock.js @@ -26,12 +26,16 @@ const mocks = { function mockCall(command, apiCommandParameters, tag) { const mockResponse = mocks[command] && mocks[command](apiCommandParameters); - if (!mockResponse || !_.isArray(mockResponse.onyxData)) { - Log.warn(`[${tag}] for command ${command} is not mocked yet!`); + if (!mockResponse) { + Log.warn(`[${tag}] for command ${command} is not mocked yet! ⚠️`); return; } - return Onyx.update(mockResponse.onyxData); + if (_.isArray(mockResponse.onyxData)) { + return Onyx.update(mockResponse.onyxData); + } + + return Promise.resolve(mockResponse); } /** From 47f7e7305c57cbee8cc845296384eedf60d309e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Wed, 25 Oct 2023 09:23:17 +0200 Subject: [PATCH 11/30] wip: navigate to report --- src/libs/E2E/tests/chatTypingTest.e2e.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libs/E2E/tests/chatTypingTest.e2e.js b/src/libs/E2E/tests/chatTypingTest.e2e.js index 50b003e966d5..95d0766ff6c2 100644 --- a/src/libs/E2E/tests/chatTypingTest.e2e.js +++ b/src/libs/E2E/tests/chatTypingTest.e2e.js @@ -1,6 +1,9 @@ import E2ELogin from '../actions/e2eLogin'; import Performance from '../../Performance'; import E2EClient from '../client'; +import Navigation from '../../Navigation/Navigation'; +import ROUTES from '../../../ROUTES'; +import CONST from '../../../CONST'; const test = () => { // check for login (if already logged in the action will simply resolve) @@ -17,7 +20,7 @@ const test = () => { Performance.subscribeToMeasurements((entry) => { if (entry.name === CONST.TIMING.SIDEBAR_LOADED) { console.debug(`[E2E] Sidebar loaded, navigating to a report…`); - Navigation.navigate(ROUTES.SEARCH); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute('98345625')); } }); }); From e35656b864208db60e8920c449269400ca8084e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Wed, 25 Oct 2023 09:32:00 +0200 Subject: [PATCH 12/30] add more mock data --- src/libs/E2E/apiMocks/openReport.js | 1938 ++++++++++++++++++++++++++- 1 file changed, 1908 insertions(+), 30 deletions(-) diff --git a/src/libs/E2E/apiMocks/openReport.js b/src/libs/E2E/apiMocks/openReport.js index 936f9d77ef06..b20b3df35bad 100644 --- a/src/libs/E2E/apiMocks/openReport.js +++ b/src/libs/E2E/apiMocks/openReport.js @@ -6,91 +6,1969 @@ export default () => ({ value: { reportID: '98345625', reportName: 'Chat Report', + type: 'chat', chatType: '', + ownerEmail: '__fake__', ownerAccountID: 0, + managerEmail: '__fake__', + managerID: 0, policyID: '_FAKE_', - participantAccountIDs: [2, 1, 4, 3, 5, 16, 18, 19], + participantAccountIDs: [14567013], isPinned: false, - lastReadCreated: '1980-01-01 00:00:00.000', - lastVisibleActionCreated: '2022-08-01 20:49:11', - lastMessageTimestamp: 1659386951000, - lastMessageText: 'Say hello\ud83d\ude10', - lastActorAccountID: 10773236, + lastReadTime: '2023-09-14 11:50:21.768', + lastMentionedTime: '2023-07-27 07:37:43.100', + lastReadSequenceNumber: 0, + lastVisibleActionCreated: '2023-08-29 12:38:16.070', + lastVisibleActionLastModified: '2023-08-29 12:38:16.070', + lastMessageText: 'terry+hightraffic@margelo.io owes \u20ac12.00', + lastActorAccountID: 14567013, notificationPreference: 'always', + welcomeMessage: '', stateNum: 0, statusNum: 0, oldPolicyName: '', visibility: null, isOwnPolicyExpenseChat: false, - lastMessageHtml: 'Say hello\ud83d\ude10', + lastMessageHtml: 'terry+hightraffic@margelo.io owes \u20ac12.00', + iouReportID: 206636935813547, hasOutstandingIOU: false, + hasOutstandingChildRequest: false, + policyName: null, + hasParentAccess: null, + parentReportID: null, + parentReportActionID: null, + writeCapability: 'all', + description: null, + isDeletedParentAction: null, + total: 0, + currency: 'USD', + submitterPayPalMeAddress: '', + chatReportID: null, + isWaitingOnBankAccount: false, + }, + }, + { + onyxMethod: 'mergecollection', + key: 'transactions_', + value: { + transactions_5509240412000765850: { + amount: 1200, + billable: false, + cardID: 15467728, + category: '', + comment: { + comment: '', + }, + created: '2023-08-29', + currency: 'EUR', + filename: '', + merchant: 'Request', + modifiedAmount: 0, + modifiedCreated: '', + modifiedCurrency: '', + modifiedMerchant: '', + originalAmount: 0, + originalCurrency: '', + parentTransactionID: '', + receipt: {}, + reimbursable: true, + reportID: '206636935813547', + status: 'Pending', + tag: '', + transactionID: '5509240412000765850', + hasEReceipt: false, + }, }, }, { onyxMethod: 'merge', key: 'reportActions_98345625', value: { - 226245034: { - reportActionID: '226245034', - actionName: 'CREATED', - created: '2022-08-01 20:48:58', - timestamp: 1659386938, - reportActionTimestamp: 0, - avatar: 'https://d2k5nsl2zxldvw.cloudfront.net/images/avatars/avatar_3.png', + '885570376575240776': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: '', + text: '', + isEdited: true, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + edits: [], + html: '', + lastModified: '2023-09-01 07:43:29.374', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-08-31 07:23:52.892', + timestamp: 1693466632, + reportActionTimestamp: 1693466632892, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '885570376575240776', + previousReportActionID: '6576518341807837187', + lastModified: '2023-09-01 07:43:29.374', + whisperedToAccountIDs: [], + }, + '6576518341807837187': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'terry+hightraffic@margelo.io owes \u20ac12.00', + text: 'terry+hightraffic@margelo.io owes \u20ac12.00', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + lastModified: '2023-08-29 12:38:16.070', + linkedReportID: '206636935813547', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-08-29 12:38:16.070', + timestamp: 1693312696, + reportActionTimestamp: 1693312696070, + automatic: false, + actionName: 'REPORTPREVIEW', + shouldShow: true, + reportActionID: '6576518341807837187', + previousReportActionID: '2658221912430757962', + lastModified: '2023-08-29 12:38:16.070', + childReportID: 206636935813547, + childType: 'iou', + childStatusNum: 1, + childStateNum: 1, + childMoneyRequestCount: 1, + whisperedToAccountIDs: [], + }, + '2658221912430757962': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'Hshshdhdhejje
Cuududdke

F
D
R
D
R
Jfj c
D

D
D
R
D
R', + text: 'Hshshdhdhejje\nCuududdke\n\nF\nD\nR\nD\nR\nJfj c\nD\n\nD\nD\nR\nD\nR', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [ + { + emoji: 'heart', + users: [ + { + accountID: 12883048, + skinTone: -1, + }, + ], + }, + ], + }, + ], + originalMessage: { + html: 'Hshshdhdhejje
Cuududdke

F
D
R
D
R
Jfj c
D

D
D
R
D
R', + lastModified: '2023-08-25 12:39:48.121', + reactions: [ + { + emoji: 'heart', + users: [ + { + accountID: 12883048, + skinTone: -1, + }, + ], + }, + ], + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-08-25 08:54:06.972', + timestamp: 1692953646, + reportActionTimestamp: 1692953646972, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '2658221912430757962', + previousReportActionID: '6551789403725495383', + lastModified: '2023-08-25 12:39:48.121', + childReportID: 1411015346900020, + childType: 'chat', + childOldestFourAccountIDs: '12883048', + childCommenterCount: 1, + childLastVisibleActionCreated: '2023-08-29 06:08:59.247', + childVisibleActionCount: 1, + whisperedToAccountIDs: [], + }, + '6551789403725495383': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'Typing with the composer is now also reasonably fast again', + text: 'Typing with the composer is now also reasonably fast again', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'Typing with the composer is now also reasonably fast again', + lastModified: '2023-08-25 08:53:57.490', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-08-25 08:53:57.490', + timestamp: 1692953637, + reportActionTimestamp: 1692953637490, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '6551789403725495383', + previousReportActionID: '6184477005811241106', + lastModified: '2023-08-25 08:53:57.490', + whisperedToAccountIDs: [], + }, + '6184477005811241106': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: '\ud83d\ude3a', + text: '\ud83d\ude3a', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: '\ud83d\ude3a', + lastModified: '2023-08-25 08:53:41.689', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-08-25 08:53:41.689', + timestamp: 1692953621, + reportActionTimestamp: 1692953621689, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '6184477005811241106', + previousReportActionID: '7473953427765241164', + lastModified: '2023-08-25 08:53:41.689', + whisperedToAccountIDs: [], + }, + '7473953427765241164': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'Skkkkkkrrrrrrrr', + text: 'Skkkkkkrrrrrrrr', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'Skkkkkkrrrrrrrr', + lastModified: '2023-08-25 08:53:31.900', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-08-25 08:53:31.900', + timestamp: 1692953611, + reportActionTimestamp: 1692953611900, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '7473953427765241164', + previousReportActionID: '872421684593496491', + lastModified: '2023-08-25 08:53:31.900', + whisperedToAccountIDs: [], + }, + '872421684593496491': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'hello this is a new test will my version sync though? i doubt it lolasdasdasdaoe f t asdasd okay und das ging jetzt eh oder? ja schaut ganz gut aus okay geht das immer noch ? schaut gut aus ja true ghw test test 2 test 4 tse 3 oida', + text: 'hello this is a new test will my version sync though? i doubt it lolasdasdasdaoe f t asdasd okay und das ging jetzt eh oder? ja schaut ganz gut aus okay geht das immer noch ? schaut gut aus ja true ghw test test 2 test 4 tse 3 oida', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'hello this is a new test will my version sync though? i doubt it lolasdasdasdaoe f t asdasd okay und das ging jetzt eh oder? ja schaut ganz gut aus okay geht das immer noch ? schaut gut aus ja true ghw test test 2 test 4 tse 3 oida', + lastModified: '2023-08-11 13:35:03.962', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-08-11 13:35:03.962', + timestamp: 1691760903, + reportActionTimestamp: 1691760903962, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '872421684593496491', + previousReportActionID: '175680146540578558', + lastModified: '2023-08-11 13:35:03.962', + whisperedToAccountIDs: [], + }, + '175680146540578558': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: '', + text: '[Attachment]', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: '', + lastModified: '2023-08-10 06:59:21.381', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-08-10 06:59:21.381', + timestamp: 1691650761, + reportActionTimestamp: 1691650761381, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '175680146540578558', + previousReportActionID: '1264289784533901723', + lastModified: '2023-08-10 06:59:21.381', + whisperedToAccountIDs: [], + }, + '1264289784533901723': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: '', + text: '[Attachment]', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: '', + lastModified: '2023-08-10 06:59:16.922', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-08-10 06:59:16.922', + timestamp: 1691650756, + reportActionTimestamp: 1691650756922, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '1264289784533901723', + previousReportActionID: '4870277010164688289', + lastModified: '2023-08-10 06:59:16.922', + whisperedToAccountIDs: [], + }, + '4870277010164688289': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'send test', + text: 'send test', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'send test', + lastModified: '2023-08-09 06:43:25.209', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-08-09 06:43:25.209', + timestamp: 1691563405, + reportActionTimestamp: 1691563405209, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '4870277010164688289', + previousReportActionID: '7931783095143103530', + lastModified: '2023-08-09 06:43:25.209', + whisperedToAccountIDs: [], + }, + '7931783095143103530': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'hello terry \ud83d\ude04 this is a test @terry+hightraffic@margelo.io', + text: 'hello terry \ud83d\ude04 this is a test @terry+hightraffic@margelo.io', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'hello terry \ud83d\ude04 this is a test @terry+hightraffic@margelo.io', + lastModified: '2023-08-08 14:38:45.035', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-08-08 14:38:45.035', + timestamp: 1691505525, + reportActionTimestamp: 1691505525035, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '7931783095143103530', + previousReportActionID: '4598496324774172433', + lastModified: '2023-08-08 14:38:45.035', + whisperedToAccountIDs: [], + }, + '4598496324774172433': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, message: [ + { + type: 'COMMENT', + html: '\ud83d\uddff', + text: '\ud83d\uddff', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: '\ud83d\uddff', + lastModified: '2023-08-08 13:21:42.102', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-08-08 13:21:42.102', + timestamp: 1691500902, + reportActionTimestamp: 1691500902102, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '4598496324774172433', + previousReportActionID: '3324110555952451144', + lastModified: '2023-08-08 13:21:42.102', + whisperedToAccountIDs: [], + }, + '3324110555952451144': { + person: [ { type: 'TEXT', style: 'strong', - text: '__fake__', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'test \ud83d\uddff', + text: 'test \ud83d\uddff', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], }, + ], + originalMessage: { + html: 'test \ud83d\uddff', + lastModified: '2023-08-08 13:21:32.101', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-08-08 13:21:32.101', + timestamp: 1691500892, + reportActionTimestamp: 1691500892101, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '3324110555952451144', + previousReportActionID: '5389364980227777980', + lastModified: '2023-08-08 13:21:32.101', + whisperedToAccountIDs: [], + }, + '5389364980227777980': { + person: [ { type: 'TEXT', - style: 'normal', - text: ' created this report', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'okay now it will work again y \ud83d\udc42', + text: 'okay now it will work again y \ud83d\udc42', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], }, ], + originalMessage: { + html: 'okay now it will work again y \ud83d\udc42', + lastModified: '2023-08-07 10:54:38.141', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-08-07 10:54:38.141', + timestamp: 1691405678, + reportActionTimestamp: 1691405678141, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '5389364980227777980', + previousReportActionID: '4717622390560689493', + lastModified: '2023-08-07 10:54:38.141', + whisperedToAccountIDs: [], + }, + '4717622390560689493': { person: [ { type: 'TEXT', style: 'strong', - text: '__fake__', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'hmmmm', + text: 'hmmmm', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], }, ], + originalMessage: { + html: 'hmmmm', + lastModified: '2023-07-27 18:13:45.322', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-07-27 18:13:45.322', + timestamp: 1690481625, + reportActionTimestamp: 1690481625322, automatic: false, + actionName: 'ADDCOMMENT', shouldShow: true, + reportActionID: '4717622390560689493', + previousReportActionID: '745721424446883075', + lastModified: '2023-07-27 18:13:45.322', + whisperedToAccountIDs: [], }, - 1082059149: { + '745721424446883075': { person: [ { type: 'TEXT', style: 'strong', - text: '123 Ios', + text: 'Hanno J. G\u00f6decke', }, ], - actorAccountID: 10773236, + actorAccountID: 12883048, message: [ { type: 'COMMENT', - html: 'Say hello\ud83d\ude10', - text: 'Say hello\ud83d\ude10', + html: 'test', + text: 'test', isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], }, ], originalMessage: { - html: 'Say hello\ud83d\ude10', + html: 'test', + lastModified: '2023-07-27 18:13:32.595', }, - avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/301e37631eca9e3127d6b668822e3a53771551f6_128.jpeg', - created: '2022-08-01 20:49:11', - timestamp: 1659386951, - reportActionTimestamp: 1659386951000, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-07-27 18:13:32.595', + timestamp: 1690481612, + reportActionTimestamp: 1690481612595, automatic: false, actionName: 'ADDCOMMENT', shouldShow: true, - reportActionID: '1082059149', + reportActionID: '745721424446883075', + previousReportActionID: '3986429677777110818', + lastModified: '2023-07-27 18:13:32.595', + whisperedToAccountIDs: [], + }, + '3986429677777110818': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'I will', + text: 'I will', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'I will', + lastModified: '2023-07-27 17:03:11.250', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 17:03:11.250', + timestamp: 1690477391, + reportActionTimestamp: 1690477391250, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '3986429677777110818', + previousReportActionID: '7317910228472011573', + lastModified: '2023-07-27 17:03:11.250', + childReportID: 3338245207149134, + childType: 'chat', + whisperedToAccountIDs: [], + }, + '7317910228472011573': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'will you>', + text: 'will you>', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'will you>', + lastModified: '2023-07-27 16:46:58.988', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-07-27 16:46:58.988', + timestamp: 1690476418, + reportActionTimestamp: 1690476418988, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '7317910228472011573', + previousReportActionID: '6779343397958390319', + lastModified: '2023-07-27 16:46:58.988', + whisperedToAccountIDs: [], + }, + '6779343397958390319': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'i will always send :#', + text: 'i will always send :#', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'i will always send :#', + lastModified: '2023-07-27 07:55:33.468', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:55:33.468', + timestamp: 1690444533, + reportActionTimestamp: 1690444533468, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '6779343397958390319', + previousReportActionID: '5084145419388195535', + lastModified: '2023-07-27 07:55:33.468', + whisperedToAccountIDs: [], + }, + '5084145419388195535': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'new test', + text: 'new test', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'new test', + lastModified: '2023-07-27 07:55:22.309', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:55:22.309', + timestamp: 1690444522, + reportActionTimestamp: 1690444522309, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '5084145419388195535', + previousReportActionID: '6742067600980190659', + lastModified: '2023-07-27 07:55:22.309', + whisperedToAccountIDs: [], + }, + '6742067600980190659': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'okay good', + text: 'okay good', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'okay good', + lastModified: '2023-07-27 07:55:15.362', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:55:15.362', + timestamp: 1690444515, + reportActionTimestamp: 1690444515362, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '6742067600980190659', + previousReportActionID: '7811212427986810247', + lastModified: '2023-07-27 07:55:15.362', + whisperedToAccountIDs: [], + }, + '7811212427986810247': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'test 2', + text: 'test 2', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'test 2', + lastModified: '2023-07-27 07:55:10.629', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:55:10.629', + timestamp: 1690444510, + reportActionTimestamp: 1690444510629, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '7811212427986810247', + previousReportActionID: '4544757211729131829', + lastModified: '2023-07-27 07:55:10.629', + whisperedToAccountIDs: [], + }, + '4544757211729131829': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'new test', + text: 'new test', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'new test', + lastModified: '2023-07-27 07:53:41.960', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:53:41.960', + timestamp: 1690444421, + reportActionTimestamp: 1690444421960, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '4544757211729131829', + previousReportActionID: '8290114634148431001', + lastModified: '2023-07-27 07:53:41.960', + whisperedToAccountIDs: [], + }, + '8290114634148431001': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'something was real', + text: 'something was real', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'something was real', + lastModified: '2023-07-27 07:53:27.836', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:53:27.836', + timestamp: 1690444407, + reportActionTimestamp: 1690444407836, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '8290114634148431001', + previousReportActionID: '5597494166918965742', + lastModified: '2023-07-27 07:53:27.836', + whisperedToAccountIDs: [], + }, + '5597494166918965742': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'oida', + text: 'oida', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'oida', + lastModified: '2023-07-27 07:53:20.783', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:53:20.783', + timestamp: 1690444400, + reportActionTimestamp: 1690444400783, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '5597494166918965742', + previousReportActionID: '7445709165354739065', + lastModified: '2023-07-27 07:53:20.783', + whisperedToAccountIDs: [], + }, + '7445709165354739065': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'test 12', + text: 'test 12', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'test 12', + lastModified: '2023-07-27 07:53:17.393', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:53:17.393', + timestamp: 1690444397, + reportActionTimestamp: 1690444397393, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '7445709165354739065', + previousReportActionID: '1985264407541504554', + lastModified: '2023-07-27 07:53:17.393', + whisperedToAccountIDs: [], + }, + '1985264407541504554': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'new test', + text: 'new test', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'new test', + lastModified: '2023-07-27 07:53:07.894', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:53:07.894', + timestamp: 1690444387, + reportActionTimestamp: 1690444387894, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '1985264407541504554', + previousReportActionID: '6101278009725036288', + lastModified: '2023-07-27 07:53:07.894', + whisperedToAccountIDs: [], + }, + '6101278009725036288': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'grrr', + text: 'grrr', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'grrr', + lastModified: '2023-07-27 07:52:56.421', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:52:56.421', + timestamp: 1690444376, + reportActionTimestamp: 1690444376421, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '6101278009725036288', + previousReportActionID: '6913024396112106680', + lastModified: '2023-07-27 07:52:56.421', + whisperedToAccountIDs: [], + }, + '6913024396112106680': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'ne w test', + text: 'ne w test', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'ne w test', + lastModified: '2023-07-27 07:52:53.352', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:52:53.352', + timestamp: 1690444373, + reportActionTimestamp: 1690444373352, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '6913024396112106680', + previousReportActionID: '3663318486255461038', + lastModified: '2023-07-27 07:52:53.352', + whisperedToAccountIDs: [], + }, + '3663318486255461038': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'well', + text: 'well', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'well', + lastModified: '2023-07-27 07:52:47.044', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:52:47.044', + timestamp: 1690444367, + reportActionTimestamp: 1690444367044, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '3663318486255461038', + previousReportActionID: '6652909175804277965', + lastModified: '2023-07-27 07:52:47.044', + whisperedToAccountIDs: [], + }, + '6652909175804277965': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'hu', + text: 'hu', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'hu', + lastModified: '2023-07-27 07:52:43.489', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:52:43.489', + timestamp: 1690444363, + reportActionTimestamp: 1690444363489, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '6652909175804277965', + previousReportActionID: '4738491624635492834', + lastModified: '2023-07-27 07:52:43.489', + whisperedToAccountIDs: [], + }, + '4738491624635492834': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'test', + text: 'test', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'test', + lastModified: '2023-07-27 07:52:40.145', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:52:40.145', + timestamp: 1690444360, + reportActionTimestamp: 1690444360145, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '4738491624635492834', + previousReportActionID: '1621235410433805703', + lastModified: '2023-07-27 07:52:40.145', + whisperedToAccountIDs: [], + }, + '1621235410433805703': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'test 4', + text: 'test 4', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'test 4', + lastModified: '2023-07-27 07:48:36.809', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-07-27 07:48:36.809', + timestamp: 1690444116, + reportActionTimestamp: 1690444116809, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '1621235410433805703', + previousReportActionID: '1024550225871474566', + lastModified: '2023-07-27 07:48:36.809', + whisperedToAccountIDs: [], + }, + '1024550225871474566': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'test 3', + text: 'test 3', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'test 3', + lastModified: '2023-07-27 07:48:24.183', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:48:24.183', + timestamp: 1690444104, + reportActionTimestamp: 1690444104183, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '1024550225871474566', + previousReportActionID: '5598482410513625723', + lastModified: '2023-07-27 07:48:24.183', + whisperedToAccountIDs: [], + }, + '5598482410513625723': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'test2', + text: 'test2', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'test2', + lastModified: '2023-07-27 07:42:25.340', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:42:25.340', + timestamp: 1690443745, + reportActionTimestamp: 1690443745340, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '5598482410513625723', + previousReportActionID: '115121137377026405', + lastModified: '2023-07-27 07:42:25.340', + whisperedToAccountIDs: [], + }, + '115121137377026405': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'test', + text: 'test', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'test', + lastModified: '2023-07-27 07:42:22.583', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-07-27 07:42:22.583', + timestamp: 1690443742, + reportActionTimestamp: 1690443742583, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '115121137377026405', + previousReportActionID: '2167420855737359171', + lastModified: '2023-07-27 07:42:22.583', + whisperedToAccountIDs: [], + }, + '2167420855737359171': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'new message', + text: 'new message', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'new message', + lastModified: '2023-07-27 07:42:09.177', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:42:09.177', + timestamp: 1690443729, + reportActionTimestamp: 1690443729177, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '2167420855737359171', + previousReportActionID: '6106926938128802897', + lastModified: '2023-07-27 07:42:09.177', + whisperedToAccountIDs: [], + }, + '6106926938128802897': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'oh', + text: 'oh', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'oh', + lastModified: '2023-07-27 07:42:03.902', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:42:03.902', + timestamp: 1690443723, + reportActionTimestamp: 1690443723902, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '6106926938128802897', + previousReportActionID: '4366704007455141347', + lastModified: '2023-07-27 07:42:03.902', + whisperedToAccountIDs: [], + }, + '4366704007455141347': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'hm lol', + text: 'hm lol', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'hm lol', + lastModified: '2023-07-27 07:42:00.734', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:42:00.734', + timestamp: 1690443720, + reportActionTimestamp: 1690443720734, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '4366704007455141347', + previousReportActionID: '2078794664797360607', + lastModified: '2023-07-27 07:42:00.734', + whisperedToAccountIDs: [], + }, + '2078794664797360607': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'hi?', + text: 'hi?', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'hi?', + lastModified: '2023-07-27 07:41:49.724', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:41:49.724', + timestamp: 1690443709, + reportActionTimestamp: 1690443709724, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '2078794664797360607', + previousReportActionID: '2030060194258527427', + lastModified: '2023-07-27 07:41:49.724', + whisperedToAccountIDs: [], + }, + '2030060194258527427': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'lets have a thread about it, will ya?', + text: 'lets have a thread about it, will ya?', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'lets have a thread about it, will ya?', + lastModified: '2023-07-27 07:40:49.146', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-07-27 07:40:49.146', + timestamp: 1690443649, + reportActionTimestamp: 1690443649146, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '2030060194258527427', + previousReportActionID: '5540483153987237906', + lastModified: '2023-07-27 07:40:49.146', + childReportID: 5860710623453234, + childType: 'chat', + childOldestFourAccountIDs: '14567013,12883048', + childCommenterCount: 2, + childLastVisibleActionCreated: '2023-07-27 07:41:03.550', + childVisibleActionCount: 2, + whisperedToAccountIDs: [], + }, + '5540483153987237906': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: '@hanno@margelo.io i mention you lasagna :)', + text: '@hanno@margelo.io i mention you lasagna :)', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: '@hanno@margelo.io i mention you lasagna :)', + lastModified: '2023-07-27 07:37:43.100', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:37:43.100', + timestamp: 1690443463, + reportActionTimestamp: 1690443463100, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '5540483153987237906', + previousReportActionID: '8050559753491913991', + lastModified: '2023-07-27 07:37:43.100', + whisperedToAccountIDs: [], + }, + '8050559753491913991': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: '@terry+hightraffic@margelo.io', + text: '@terry+hightraffic@margelo.io', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: '@terry+hightraffic@margelo.io', + lastModified: '2023-07-27 07:36:41.708', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:36:41.708', + timestamp: 1690443401, + reportActionTimestamp: 1690443401708, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '8050559753491913991', + previousReportActionID: '881015235172878574', + lastModified: '2023-07-27 07:36:41.708', + whisperedToAccountIDs: [], + }, + '881015235172878574': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'yeah lets see', + text: 'yeah lets see', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'yeah lets see', + lastModified: '2023-07-27 07:25:15.997', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-27 07:25:15.997', + timestamp: 1690442715, + reportActionTimestamp: 1690442715997, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '881015235172878574', + previousReportActionID: '4800357767877651330', + lastModified: '2023-07-27 07:25:15.997', + whisperedToAccountIDs: [], + }, + '4800357767877651330': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'asdasdasd', + text: 'asdasdasd', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'asdasdasd', + lastModified: '2023-07-27 07:25:03.093', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-07-27 07:25:03.093', + timestamp: 1690442703, + reportActionTimestamp: 1690442703093, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '4800357767877651330', + previousReportActionID: '9012557872554910346', + lastModified: '2023-07-27 07:25:03.093', + whisperedToAccountIDs: [], + }, + '9012557872554910346': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'yeah', + text: 'yeah', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'yeah', + lastModified: '2023-07-26 19:49:40.471', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-26 19:49:40.471', + timestamp: 1690400980, + reportActionTimestamp: 1690400980471, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '9012557872554910346', + previousReportActionID: '8440677969068645500', + lastModified: '2023-07-26 19:49:40.471', + whisperedToAccountIDs: [], + }, + '8440677969068645500': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'hello motor', + text: 'hello motor', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'hello motor', + lastModified: '2023-07-26 19:49:36.262', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-07-26 19:49:36.262', + timestamp: 1690400976, + reportActionTimestamp: 1690400976262, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '8440677969068645500', + previousReportActionID: '306887996337608775', + lastModified: '2023-07-26 19:49:36.262', + whisperedToAccountIDs: [], + }, + '306887996337608775': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'a new messagfe', + text: 'a new messagfe', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'a new messagfe', + lastModified: '2023-07-26 19:49:29.512', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-07-26 19:49:29.512', + timestamp: 1690400969, + reportActionTimestamp: 1690400969512, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '306887996337608775', + previousReportActionID: '587892433077506227', + lastModified: '2023-07-26 19:49:29.512', + whisperedToAccountIDs: [], + }, + '587892433077506227': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Hanno J. G\u00f6decke', + }, + ], + actorAccountID: 12883048, + message: [ + { + type: 'COMMENT', + html: 'good', + text: 'good', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'good', + lastModified: '2023-07-26 19:49:20.473', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/fc1b8880216a5a76c8fd9998aaa33c080dacda5d_128.jpeg', + created: '2023-07-26 19:49:20.473', + timestamp: 1690400960, + reportActionTimestamp: 1690400960473, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '587892433077506227', + previousReportActionID: '1433103421804347060', + lastModified: '2023-07-26 19:49:20.473', + whisperedToAccountIDs: [], + }, + '1433103421804347060': { + person: [ + { + type: 'TEXT', + style: 'strong', + text: 'Terry Hightraffic1337', + }, + ], + actorAccountID: 14567013, + message: [ + { + type: 'COMMENT', + html: 'ah', + text: 'ah', + isEdited: false, + whisperedTo: [], + isDeletedParentAction: false, + reactions: [], + }, + ], + originalMessage: { + html: 'ah', + lastModified: '2023-07-26 19:49:12.762', + }, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + created: '2023-07-26 19:49:12.762', + timestamp: 1690400952, + reportActionTimestamp: 1690400952762, + automatic: false, + actionName: 'ADDCOMMENT', + shouldShow: true, + reportActionID: '1433103421804347060', + previousReportActionID: '8774157052628183778', + lastModified: '2023-07-26 19:49:12.762', + whisperedToAccountIDs: [], + }, + }, + }, + { + onyxMethod: 'mergecollection', + key: 'reportActionsReactions_', + value: { + reportActionsReactions_2658221912430757962: { + heart: { + createdAt: '2023-08-25 12:37:45', + users: { + 12883048: { + skinTones: { + '-1': '2023-08-25 12:37:45', + }, + }, + }, + }, + }, + }, + }, + { + onyxMethod: 'merge', + key: 'personalDetailsList', + value: { + 14567013: { + accountID: 14567013, + avatar: 'https://d1wpcgnaa73g0y.cloudfront.net/49a4c96c366f9a32905b30462f91ea39e5eee5e8_128.jpeg', + displayName: 'Terry Hightraffic1337', + firstName: 'Terry', + lastName: 'Hightraffic1337', + status: null, + login: 'terry+hightraffic@margelo.io', + pronouns: '', + timezone: { + automatic: true, + selected: 'Europe/Kiev', + }, + payPalMeAddress: '', + phoneNumber: '', + validated: true, }, }, }, ], jsonCode: 200, - requestID: '783ef80a3fc5969a-SJC', + requestID: '81b8b8509a7f5b54-VIE', }); From 881630798fbea58673ad023fd60a802dde9138e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Wed, 25 Oct 2023 09:34:25 +0200 Subject: [PATCH 13/30] add mock for read newest action --- src/libs/E2E/API.mock.js | 2 ++ src/libs/E2E/apiMocks/readNewestAction.js | 13 +++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/libs/E2E/apiMocks/readNewestAction.js diff --git a/src/libs/E2E/API.mock.js b/src/libs/E2E/API.mock.js index ba85cd19aac3..fda1c0d86073 100644 --- a/src/libs/E2E/API.mock.js +++ b/src/libs/E2E/API.mock.js @@ -9,6 +9,7 @@ import mockSigninUser from './apiMocks/signinUser'; import mockAuthenticatePusher from './apiMocks/authenticatePusher'; import mockOpenApp from './apiMocks/openApp'; import mockOpenReport from './apiMocks/openReport'; +import mockReadNewestAction from './apiMocks/readNewestAction'; /** * A dictionary which has the name of a API command as key, and a function which @@ -22,6 +23,7 @@ const mocks = { ReconnectApp: mockOpenApp, OpenReport: mockOpenReport, AuthenticatePusher: mockAuthenticatePusher, + ReadNewestAction: mockReadNewestAction, }; function mockCall(command, apiCommandParameters, tag) { diff --git a/src/libs/E2E/apiMocks/readNewestAction.js b/src/libs/E2E/apiMocks/readNewestAction.js new file mode 100644 index 000000000000..04270a8d93f4 --- /dev/null +++ b/src/libs/E2E/apiMocks/readNewestAction.js @@ -0,0 +1,13 @@ +export default () => ({ + jsonCode: 200, + requestID: '81b8c48e3bfe5a84-VIE', + onyxData: [ + { + onyxMethod: 'merge', + key: 'report_98345625', + value: { + lastReadTime: '2023-10-25 07:32:48.915', + }, + }, + ], +}); From 9655acdaf6810dbc31fdfd3bb1f9cb68302a8975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Wed, 25 Oct 2023 09:37:07 +0200 Subject: [PATCH 14/30] add mock for ReconnectToReport --- src/libs/E2E/API.mock.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/E2E/API.mock.js b/src/libs/E2E/API.mock.js index fda1c0d86073..cbe3687ac3c5 100644 --- a/src/libs/E2E/API.mock.js +++ b/src/libs/E2E/API.mock.js @@ -22,6 +22,7 @@ const mocks = { OpenApp: mockOpenApp, ReconnectApp: mockOpenApp, OpenReport: mockOpenReport, + ReconnectToReport: mockOpenReport, AuthenticatePusher: mockAuthenticatePusher, ReadNewestAction: mockReadNewestAction, }; From 8dfd4ab09e182482b92e4fd48833543ea781579e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 27 Oct 2023 10:52:04 +0200 Subject: [PATCH 15/30] wip: having a .e2e.js component --- metro.config.js | 11 +-- src/libs/E2E/client.js | 22 ++++++ src/libs/E2E/tests/chatTypingTest.e2e.js | 11 ++- .../ComposerWithSuggestions.js | 67 ++++++++++--------- .../composerWithSuggestionsProps.js | 4 +- .../ComposerWithSuggestions/index.e2e.js | 13 ++++ tests/e2e/ADDING_TESTS.md | 2 +- .../nativeCommands/NativeCommandsAction.js | 2 +- 8 files changed, 89 insertions(+), 43 deletions(-) rename src/pages/home/report/ReportActionCompose/{ => ComposerWithSuggestions}/ComposerWithSuggestions.js (91%) rename src/pages/home/report/ReportActionCompose/{ => ComposerWithSuggestions}/composerWithSuggestionsProps.js (97%) create mode 100644 src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.js diff --git a/metro.config.js b/metro.config.js index 62ca2a25c6b2..dd391c86c34c 100644 --- a/metro.config.js +++ b/metro.config.js @@ -6,13 +6,15 @@ require('dotenv').config(); const defaultConfig = getDefaultConfig(__dirname); -const isUsingMockAPI = process.env.E2E_TESTING === 'true'; +const isE2ETesting = process.env.E2E_TESTING === 'true'; -if (isUsingMockAPI) { +if (isE2ETesting) { // eslint-disable-next-line no-console console.log('⚠️⚠️⚠️⚠️ Using mock API ⚠️⚠️⚠️⚠️'); } +const e2eSourceExts = ['e2e.js', 'e2e.ts']; + /** * Metro configuration * https://facebook.github.io/metro/docs/configuration @@ -22,10 +24,11 @@ if (isUsingMockAPI) { const config = { resolver: { assetExts: _.filter(defaultAssetExts, (ext) => ext !== 'svg'), - sourceExts: [...defaultSourceExts, 'jsx', 'svg'], + // When we run the e2e tests we want files that have the extension e2e.js to be resolved as source files + sourceExts: [...(isE2ETesting ? e2eSourceExts : []), ...defaultSourceExts, 'jsx', 'svg'], resolveRequest: (context, moduleName, platform) => { const resolution = context.resolveRequest(context, moduleName, platform); - if (isUsingMockAPI && moduleName.includes('/API')) { + 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'); // eslint-disable-next-line no-console diff --git a/src/libs/E2E/client.js b/src/libs/E2E/client.js index c948c7c2c6d2..37d339aad48f 100644 --- a/src/libs/E2E/client.js +++ b/src/libs/E2E/client.js @@ -42,8 +42,30 @@ const getTestConfig = () => .then((res) => res.json()) .then((config) => config); +const sendNativeCommand = (payload) => + fetch(`${SERVER_ADDRESS}${Routes.testNativeCommand}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload), + }).then((res) => { + if (res.statusCode === 200) { + return; + } + const errorMsg = `Test result submission failed with status code ${res.statusCode}`; + res.json() + .then((responseText) => { + throw new Error(`${errorMsg}: ${responseText}`); + }) + .catch(() => { + throw new Error(errorMsg); + }); + }); + export default { submitTestResults, submitTestDone, getTestConfig, + sendNativeCommand, }; diff --git a/src/libs/E2E/tests/chatTypingTest.e2e.js b/src/libs/E2E/tests/chatTypingTest.e2e.js index 95d0766ff6c2..4788e463c91c 100644 --- a/src/libs/E2E/tests/chatTypingTest.e2e.js +++ b/src/libs/E2E/tests/chatTypingTest.e2e.js @@ -4,6 +4,7 @@ import E2EClient from '../client'; import Navigation from '../../Navigation/Navigation'; import ROUTES from '../../../ROUTES'; import CONST from '../../../CONST'; +import * as NativeCommands from '../../../../tests/e2e/nativeCommands/NativeCommandsAction'; const test = () => { // check for login (if already logged in the action will simply resolve) @@ -18,10 +19,14 @@ const test = () => { console.debug('[E2E] Logged in, getting typing metrics and submitting them…'); Performance.subscribeToMeasurements((entry) => { - if (entry.name === CONST.TIMING.SIDEBAR_LOADED) { - console.debug(`[E2E] Sidebar loaded, navigating to a report…`); - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute('98345625')); + if (entry.name !== CONST.TIMING.SIDEBAR_LOADED) { + return; } + + console.debug(`[E2E] Sidebar loaded, navigating to a report…`); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute('98345625')); + + E2EClient.sendNativeCommand(NativeCommands.makeTypeTextCommand('Hi')); }); }); }; diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js similarity index 91% rename from src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js rename to src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js index e194d0870885..28fc5a4c5f24 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js @@ -4,38 +4,38 @@ import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import lodashGet from 'lodash/get'; import {useIsFocused, useNavigation} from '@react-navigation/native'; -import styles from '../../../../styles/styles'; -import themeColors from '../../../../styles/themes/default'; -import Composer from '../../../../components/Composer'; -import containerComposeStyles from '../../../../styles/containerComposeStyles'; -import useWindowDimensions from '../../../../hooks/useWindowDimensions'; -import CONST from '../../../../CONST'; -import * as Browser from '../../../../libs/Browser'; -import ONYXKEYS from '../../../../ONYXKEYS'; -import * as KeyDownListener from '../../../../libs/KeyboardShortcut/KeyDownPressListener'; -import * as EmojiPickerActions from '../../../../libs/actions/EmojiPickerAction'; -import willBlurTextInputOnTapOutsideFunc from '../../../../libs/willBlurTextInputOnTapOutside'; -import ReportActionComposeFocusManager from '../../../../libs/ReportActionComposeFocusManager'; -import * as ComposerUtils from '../../../../libs/ComposerUtils'; -import * as Report from '../../../../libs/actions/Report'; -import usePrevious from '../../../../hooks/usePrevious'; -import * as EmojiUtils from '../../../../libs/EmojiUtils'; -import * as User from '../../../../libs/actions/User'; -import * as ReportUtils from '../../../../libs/ReportUtils'; -import * as SuggestionUtils from '../../../../libs/SuggestionUtils'; -import * as ReportActionsUtils from '../../../../libs/ReportActionsUtils'; -import canFocusInputOnScreenFocus from '../../../../libs/canFocusInputOnScreenFocus'; -import SilentCommentUpdater from './SilentCommentUpdater'; -import Suggestions from './Suggestions'; -import getDraftComment from '../../../../libs/ComposerUtils/getDraftComment'; -import useLocalize from '../../../../hooks/useLocalize'; -import compose from '../../../../libs/compose'; -import withKeyboardState from '../../../../components/withKeyboardState'; +import styles from '../../../../../styles/styles'; +import themeColors from '../../../../../styles/themes/default'; +import Composer from '../../../../../components/Composer'; +import containerComposeStyles from '../../../../../styles/containerComposeStyles'; +import useWindowDimensions from '../../../../../hooks/useWindowDimensions'; +import CONST from '../../../../../CONST'; +import * as Browser from '../../../../../libs/Browser'; +import ONYXKEYS from '../../../../../ONYXKEYS'; +import * as KeyDownListener from '../../../../../libs/KeyboardShortcut/KeyDownPressListener'; +import * as EmojiPickerActions from '../../../../../libs/actions/EmojiPickerAction'; +import willBlurTextInputOnTapOutsideFunc from '../../../../../libs/willBlurTextInputOnTapOutside'; +import ReportActionComposeFocusManager from '../../../../../libs/ReportActionComposeFocusManager'; +import * as ComposerUtils from '../../../../../libs/ComposerUtils'; +import * as Report from '../../../../../libs/actions/Report'; +import usePrevious from '../../../../../hooks/usePrevious'; +import * as EmojiUtils from '../../../../../libs/EmojiUtils'; +import * as User from '../../../../../libs/actions/User'; +import * as ReportUtils from '../../../../../libs/ReportUtils'; +import * as SuggestionUtils from '../../../../../libs/SuggestionUtils'; +import * as ReportActionsUtils from '../../../../../libs/ReportActionsUtils'; +import canFocusInputOnScreenFocus from '../../../../../libs/canFocusInputOnScreenFocus'; +import SilentCommentUpdater from '../SilentCommentUpdater'; +import Suggestions from '../Suggestions'; +import getDraftComment from '../../../../../libs/ComposerUtils/getDraftComment'; +import useLocalize from '../../../../../hooks/useLocalize'; +import compose from '../../../../../libs/compose'; +import withKeyboardState from '../../../../../components/withKeyboardState'; import {propTypes, defaultProps} from './composerWithSuggestionsProps'; -import focusWithDelay from '../../../../libs/focusWithDelay'; -import useDebounce from '../../../../hooks/useDebounce'; -import updateMultilineInputRange from '../../../../libs/UpdateMultilineInputRange'; -import * as InputFocus from '../../../../libs/actions/InputFocus'; +import focusWithDelay from '../../../../../libs/focusWithDelay'; +import useDebounce from '../../../../../hooks/useDebounce'; +import updateMultilineInputRange from '../../../../../libs/UpdateMultilineInputRange'; +import * as InputFocus from '../../../../../libs/actions/InputFocus'; const {RNTextInputReset} = NativeModules; @@ -522,7 +522,10 @@ function ComposerWithSuggestions({ return ( <> - + { + console.log('⚠️⚡️🤡 JOOOOO LOADING FROM e2E file brother'); + return ( + + ); +}); diff --git a/tests/e2e/ADDING_TESTS.md b/tests/e2e/ADDING_TESTS.md index ac43e61f60ed..6a4ea3edd1ef 100644 --- a/tests/e2e/ADDING_TESTS.md +++ b/tests/e2e/ADDING_TESTS.md @@ -33,7 +33,7 @@ require('./src/libs/E2E/reactNativeLaunchingTest'); Now you can start the metro bundler in e2e mode with: -``` +```bash CAPTURE_METRICS=true E2E_TESTING=true npm start -- --reset-cache ``` diff --git a/tests/e2e/nativeCommands/NativeCommandsAction.js b/tests/e2e/nativeCommands/NativeCommandsAction.js index ce6b38079527..eb3566b88b1c 100644 --- a/tests/e2e/nativeCommands/NativeCommandsAction.js +++ b/tests/e2e/nativeCommands/NativeCommandsAction.js @@ -4,7 +4,7 @@ const NativeCommandsAction = { }; const makeTypeTextCommand = (text) => ({ - command: NativeCommandsAction.type, + actionName: NativeCommandsAction.type, payload: { text, }, From 337bc06a37a5e227d92420fb906d5a1a4c529358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 27 Oct 2023 11:30:30 +0200 Subject: [PATCH 16/30] implemented typing into composer --- src/libs/E2E/actions/waitForKeyboard.js | 15 ++++++++++++ src/libs/E2E/client.js | 9 ++++++- ...ingTest.e2e.js => reportTypingTest.e2e.js} | 7 +++++- .../ComposerWithSuggestions/index.e2e.js | 24 ++++++++++++++++--- tests/e2e/config.js | 3 +++ 5 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 src/libs/E2E/actions/waitForKeyboard.js rename src/libs/E2E/tests/{chatTypingTest.e2e.js => reportTypingTest.e2e.js} (76%) diff --git a/src/libs/E2E/actions/waitForKeyboard.js b/src/libs/E2E/actions/waitForKeyboard.js new file mode 100644 index 000000000000..4bc0f492e3a3 --- /dev/null +++ b/src/libs/E2E/actions/waitForKeyboard.js @@ -0,0 +1,15 @@ +import {Keyboard} from 'react-native'; + +export default function waitForKeyboard() { + return new Promise((resolve) => { + function checkKeyboard() { + if (Keyboard.isVisible()) { + resolve(); + } else { + console.debug(`[E2E] Waiting for keyboard to appear…`); + setTimeout(checkKeyboard, 1000); + } + } + checkKeyboard(); + }); +} diff --git a/src/libs/E2E/client.js b/src/libs/E2E/client.js index 37d339aad48f..9221919bf427 100644 --- a/src/libs/E2E/client.js +++ b/src/libs/E2E/client.js @@ -34,13 +34,19 @@ const submitTestResults = (testResult) => const submitTestDone = () => fetch(`${SERVER_ADDRESS}${Routes.testDone}`); +let currentActiveTestConfig = null; /** * @returns {Promise} */ const getTestConfig = () => fetch(`${SERVER_ADDRESS}${Routes.testConfig}`) .then((res) => res.json()) - .then((config) => config); + .then((config) => { + currentActiveTestConfig = config; + return config; + }); + +const getCurrentActiveTestConfig = () => currentActiveTestConfig; const sendNativeCommand = (payload) => fetch(`${SERVER_ADDRESS}${Routes.testNativeCommand}`, { @@ -67,5 +73,6 @@ export default { submitTestResults, submitTestDone, getTestConfig, + getCurrentActiveTestConfig, sendNativeCommand, }; diff --git a/src/libs/E2E/tests/chatTypingTest.e2e.js b/src/libs/E2E/tests/reportTypingTest.e2e.js similarity index 76% rename from src/libs/E2E/tests/chatTypingTest.e2e.js rename to src/libs/E2E/tests/reportTypingTest.e2e.js index 4788e463c91c..4829b65a8b93 100644 --- a/src/libs/E2E/tests/chatTypingTest.e2e.js +++ b/src/libs/E2E/tests/reportTypingTest.e2e.js @@ -5,6 +5,7 @@ import Navigation from '../../Navigation/Navigation'; import ROUTES from '../../../ROUTES'; import CONST from '../../../CONST'; import * as NativeCommands from '../../../../tests/e2e/nativeCommands/NativeCommandsAction'; +import waitForKeyboard from '../actions/waitForKeyboard'; const test = () => { // check for login (if already logged in the action will simply resolve) @@ -26,7 +27,11 @@ const test = () => { console.debug(`[E2E] Sidebar loaded, navigating to a report…`); Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute('98345625')); - E2EClient.sendNativeCommand(NativeCommands.makeTypeTextCommand('Hi')); + // Wait until keyboard is visible (so we are focused on the input): + waitForKeyboard().then(() => { + console.debug(`[E2E] Keyboard visible, typing…`); + E2EClient.sendNativeCommand(NativeCommands.makeTypeTextCommand('Hi')); + }); }); }); }; diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.js index 63be4d49a628..276e5a82a8c3 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.js @@ -1,13 +1,31 @@ -import React from 'react'; +import React, {useEffect} from 'react'; +import _ from 'lodash'; import ComposerWithSuggestions from './ComposerWithSuggestions'; +import E2EClient from '../../../../../libs/E2E/client'; export default React.forwardRef((props, ref) => { - console.log('⚠️⚡️🤡 JOOOOO LOADING FROM e2E file brother'); + // Auto focus on e2e tests + useEffect(() => { + if (_.get(E2EClient.getCurrentActiveTestConfig(), 'reportScreen.autoFocus', false) === false) { + return; + } + + // We need to wait for the component to be mounted before focusing + setTimeout(() => { + if (!ref || !ref.current) { + console.log('No ref ⛈️'); + return; + } + + ref.current.focus(true); + }, 1); + }, [ref]); + return ( ); }); diff --git a/tests/e2e/config.js b/tests/e2e/config.js index 34cd13a8f6db..6095927d0174 100644 --- a/tests/e2e/config.js +++ b/tests/e2e/config.js @@ -66,6 +66,9 @@ module.exports = { }, [TEST_NAMES.ReportTyping]: { name: TEST_NAMES.ReportTyping, + reportScreen: { + autoFocus: true, + }, }, }, }; From 953b91d1e9ae4201f8d4fccc4b51da6561b1fcd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 27 Oct 2023 12:03:51 +0200 Subject: [PATCH 17/30] send rerender results to client --- src/libs/E2E/client.js | 14 ++++++----- src/libs/E2E/tests/reportTypingTest.e2e.js | 17 ++++++++++++- .../ComposerWithSuggestions.js | 5 ++++ .../ComposerWithSuggestions/index.e2e.js | 24 ++++++++++++++++--- tests/e2e/server/index.js | 15 ++++++------ 5 files changed, 57 insertions(+), 18 deletions(-) diff --git a/src/libs/E2E/client.js b/src/libs/E2E/client.js index 9221919bf427..0da87094683a 100644 --- a/src/libs/E2E/client.js +++ b/src/libs/E2E/client.js @@ -10,19 +10,20 @@ const SERVER_ADDRESS = `http://localhost:${Config.SERVER_PORT}`; * @param {TestResult} testResult * @returns {Promise} */ -const submitTestResults = (testResult) => - fetch(`${SERVER_ADDRESS}${Routes.testResults}`, { +const submitTestResults = (testResult) => { + console.debug(`[E2E] Submitting test result '${testResult.name}'…`); + return fetch(`${SERVER_ADDRESS}${Routes.testResults}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(testResult), }).then((res) => { - if (res.statusCode === 200) { + if (res.status === 200) { console.debug(`[E2E] Test result '${testResult.name}' submitted successfully`); return; } - const errorMsg = `Test result submission failed with status code ${res.statusCode}`; + const errorMsg = `Test result submission failed with status code ${res.status}`; res.json() .then((responseText) => { throw new Error(`${errorMsg}: ${responseText}`); @@ -31,6 +32,7 @@ const submitTestResults = (testResult) => throw new Error(errorMsg); }); }); +}; const submitTestDone = () => fetch(`${SERVER_ADDRESS}${Routes.testDone}`); @@ -57,9 +59,9 @@ const sendNativeCommand = (payload) => body: JSON.stringify(payload), }).then((res) => { if (res.statusCode === 200) { - return; + return true; } - const errorMsg = `Test result submission failed with status code ${res.statusCode}`; + const errorMsg = `Sending native command failed with status code ${res.statusCode}`; res.json() .then((responseText) => { throw new Error(`${errorMsg}: ${responseText}`); diff --git a/src/libs/E2E/tests/reportTypingTest.e2e.js b/src/libs/E2E/tests/reportTypingTest.e2e.js index 4829b65a8b93..5c1cd425f60a 100644 --- a/src/libs/E2E/tests/reportTypingTest.e2e.js +++ b/src/libs/E2E/tests/reportTypingTest.e2e.js @@ -6,6 +6,7 @@ import ROUTES from '../../../ROUTES'; import CONST from '../../../CONST'; import * as NativeCommands from '../../../../tests/e2e/nativeCommands/NativeCommandsAction'; import waitForKeyboard from '../actions/waitForKeyboard'; +import {resetRerenderCount, getRerenderCount} from '../../../pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e'; const test = () => { // check for login (if already logged in the action will simply resolve) @@ -29,8 +30,22 @@ const test = () => { // Wait until keyboard is visible (so we are focused on the input): waitForKeyboard().then(() => { + resetRerenderCount(); console.debug(`[E2E] Keyboard visible, typing…`); - E2EClient.sendNativeCommand(NativeCommands.makeTypeTextCommand('Hi')); + E2EClient.sendNativeCommand(NativeCommands.makeTypeTextCommand('A')) + .then(() => { + setTimeout(() => { + const rerenderCount = getRerenderCount(); + + E2EClient.submitTestResults({ + name: 'Composer typing rerender count', + duration: rerenderCount, + }).then(E2EClient.submitTestDone); + }, 3000); + }) + .catch(() => { + // TODO: error handling + }); }); }); }); diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js index 28fc5a4c5f24..6f885f8c6009 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js @@ -103,6 +103,8 @@ function ComposerWithSuggestions({ forwardedRef, isNextModalWillOpenRef, editFocused, + // For testing + children, }) { const {preferredLocale} = useLocalize(); const isFocused = useIsFocused(); @@ -589,6 +591,9 @@ function ComposerWithSuggestions({ updateComment={updateComment} commentRef={commentRef} /> + + {/* Only used for testing so far */} + {children} ); } diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.js index 276e5a82a8c3..ab626ac0f2e8 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.js @@ -3,8 +3,19 @@ import _ from 'lodash'; import ComposerWithSuggestions from './ComposerWithSuggestions'; import E2EClient from '../../../../../libs/E2E/client'; +let rerenderCount = 0; +const getRerenderCount = () => rerenderCount; +const resetRerenderCount = () => { + rerenderCount = 0; +}; + +function IncrementRenderCount() { + rerenderCount += 1; + return null; +} + export default React.forwardRef((props, ref) => { - // Auto focus on e2e tests + // Eventually Auto focus on e2e tests useEffect(() => { if (_.get(E2EClient.getCurrentActiveTestConfig(), 'reportScreen.autoFocus', false) === false) { return; @@ -13,7 +24,6 @@ export default React.forwardRef((props, ref) => { // We need to wait for the component to be mounted before focusing setTimeout(() => { if (!ref || !ref.current) { - console.log('No ref ⛈️'); return; } @@ -26,6 +36,14 @@ export default React.forwardRef((props, ref) => { // eslint-disable-next-line react/jsx-props-no-spreading {...props} ref={ref} - /> + > + {/* Important: + this has to be a child, as this container might not + re-render while the actual ComposerWithSuggestions will. + */} + + ); }); + +export {getRerenderCount, resetRerenderCount}; diff --git a/tests/e2e/server/index.js b/tests/e2e/server/index.js index 94b4e8abec09..f12a982745bb 100644 --- a/tests/e2e/server/index.js +++ b/tests/e2e/server/index.js @@ -127,16 +127,15 @@ const createServerInstance = () => { } case Routes.testNativeCommand: { - getPostJSONRequestData(req, res).then((data) => { - const status = executeFromPayload(data.actionName, data.payload); - if (status) { - res.end('ok'); - } else { + getPostJSONRequestData(req, res).then((data) => + executeFromPayload(data.actionName, data.payload).then((status) => { + if (status) { + return res.end('ok'); + } res.statusCode = 500; res.end('Error executing command'); - } - }); - + }), + ); break; } From 602bdbd564b8c48cbdc4b77caabe79d8ea0ce892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 27 Oct 2023 12:26:11 +0200 Subject: [PATCH 18/30] remove the connotation of "duration" --- src/libs/E2E/tests/reportTypingTest.e2e.js | 2 +- tests/e2e/testRunner.js | 24 ++++++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/libs/E2E/tests/reportTypingTest.e2e.js b/src/libs/E2E/tests/reportTypingTest.e2e.js index 5c1cd425f60a..d70579c2e733 100644 --- a/src/libs/E2E/tests/reportTypingTest.e2e.js +++ b/src/libs/E2E/tests/reportTypingTest.e2e.js @@ -39,7 +39,7 @@ const test = () => { E2EClient.submitTestResults({ name: 'Composer typing rerender count', - duration: rerenderCount, + renderCount: rerenderCount, }).then(E2EClient.submitTestDone); }, 3000); }) diff --git a/tests/e2e/testRunner.js b/tests/e2e/testRunner.js index 5c6c33bdf7e9..00cf46a6eaea 100644 --- a/tests/e2e/testRunner.js +++ b/tests/e2e/testRunner.js @@ -170,20 +170,28 @@ const runTests = async () => { const server = createServerInstance(); await server.start(); - // Create a dict in which we will store the run durations for all tests - const durationsByTestName = {}; + // Create a dict in which we will store the collected metrics for all tests + const resultsByTestName = {}; // Collect results while tests are being executed server.addTestResultListener((testResult) => { if (testResult.error != null) { throw new Error(`Test '${testResult.name}' failed with error: ${testResult.error}`); } - if (testResult.duration < 0) { - return; + let result = 0; + + if ('duration' in testResult) { + if (testResult.duration < 0) { + return; + } + result = testResult.duration; + } + if ('renderCount' in testResult) { + result = testResult.renderCount; } - Logger.log(`[LISTENER] Test '${testResult.name}' took ${testResult.duration}ms`); - durationsByTestName[testResult.name] = (durationsByTestName[testResult.name] || []).concat(testResult.duration); + Logger.log(`[LISTENER] Test '${testResult.name}' measured ${result}`); + resultsByTestName[testResult.name] = (resultsByTestName[testResult.name] || []).concat(result); }); // Run the tests @@ -255,8 +263,8 @@ const runTests = async () => { // Calculate statistics and write them to our work file progressLog = Logger.progressInfo('Calculating statics and writing results'); - for (const testName of _.keys(durationsByTestName)) { - const stats = math.getStats(durationsByTestName[testName]); + for (const testName of _.keys(resultsByTestName)) { + const stats = math.getStats(resultsByTestName[testName]); await writeTestStats( { name: testName, From 8152008640c3e06de9a1b3976faa5023bca25d6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 27 Oct 2023 13:11:34 +0200 Subject: [PATCH 19/30] add clearing of input --- src/libs/E2E/tests/reportTypingTest.e2e.js | 13 ++++++++---- .../nativeCommands/NativeCommandsAction.js | 6 ++++++ tests/e2e/nativeCommands/adbBackspace.js | 10 ++++++++++ tests/e2e/nativeCommands/index.js | 3 +++ tests/e2e/server/index.js | 20 ++++++++++++------- 5 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 tests/e2e/nativeCommands/adbBackspace.js diff --git a/src/libs/E2E/tests/reportTypingTest.e2e.js b/src/libs/E2E/tests/reportTypingTest.e2e.js index d70579c2e733..ec2ddbea013c 100644 --- a/src/libs/E2E/tests/reportTypingTest.e2e.js +++ b/src/libs/E2E/tests/reportTypingTest.e2e.js @@ -30,9 +30,13 @@ const test = () => { // Wait until keyboard is visible (so we are focused on the input): waitForKeyboard().then(() => { - resetRerenderCount(); console.debug(`[E2E] Keyboard visible, typing…`); - E2EClient.sendNativeCommand(NativeCommands.makeTypeTextCommand('A')) + E2EClient.sendNativeCommand(NativeCommands.makeBackspaceCommand()) + .then(() => { + resetRerenderCount(); + return Promise.resolve(); + }) + .then(() => E2EClient.sendNativeCommand(NativeCommands.makeTypeTextCommand('A'))) .then(() => { setTimeout(() => { const rerenderCount = getRerenderCount(); @@ -43,8 +47,9 @@ const test = () => { }).then(E2EClient.submitTestDone); }, 3000); }) - .catch(() => { - // TODO: error handling + .catch((error) => { + console.error('[E2E] Error while test', error); + E2EClient.submitTestDone(); }); }); }); diff --git a/tests/e2e/nativeCommands/NativeCommandsAction.js b/tests/e2e/nativeCommands/NativeCommandsAction.js index eb3566b88b1c..f2aa4644f7ff 100644 --- a/tests/e2e/nativeCommands/NativeCommandsAction.js +++ b/tests/e2e/nativeCommands/NativeCommandsAction.js @@ -1,6 +1,7 @@ const NativeCommandsAction = { scroll: 'scroll', type: 'type', + backspace: 'backspace', }; const makeTypeTextCommand = (text) => ({ @@ -10,7 +11,12 @@ const makeTypeTextCommand = (text) => ({ }, }); +const makeBackspaceCommand = () => ({ + actionName: NativeCommandsAction.backspace, +}); + module.exports = { NativeCommandsAction, makeTypeTextCommand, + makeBackspaceCommand, }; diff --git a/tests/e2e/nativeCommands/adbBackspace.js b/tests/e2e/nativeCommands/adbBackspace.js new file mode 100644 index 000000000000..8f41364daed3 --- /dev/null +++ b/tests/e2e/nativeCommands/adbBackspace.js @@ -0,0 +1,10 @@ +const execAsync = require('../utils/execAsync'); +const Logger = require('../utils/logger'); + +const adbBackspace = async () => { + Logger.log(`🔙 Pressing backspace`); + execAsync(`adb shell input keyevent KEYCODE_DEL`); + return true; +}; + +module.exports = adbBackspace; diff --git a/tests/e2e/nativeCommands/index.js b/tests/e2e/nativeCommands/index.js index 7452dce3067c..bb87c16a6f42 100644 --- a/tests/e2e/nativeCommands/index.js +++ b/tests/e2e/nativeCommands/index.js @@ -1,3 +1,4 @@ +const adbBackspace = require('./adbBackspace'); const adbTypeText = require('./adbTypeText'); const {NativeCommandsAction} = require('./NativeCommandsAction'); @@ -7,6 +8,8 @@ const executeFromPayload = (actionName, payload) => { throw new Error('Not implemented yet'); case NativeCommandsAction.type: return adbTypeText(payload.text); + case NativeCommandsAction.backspace: + return adbBackspace(); default: throw new Error(`Unknown action: ${actionName}`); } diff --git a/tests/e2e/server/index.js b/tests/e2e/server/index.js index f12a982745bb..51a227ed1c33 100644 --- a/tests/e2e/server/index.js +++ b/tests/e2e/server/index.js @@ -127,15 +127,21 @@ const createServerInstance = () => { } case Routes.testNativeCommand: { - getPostJSONRequestData(req, res).then((data) => - executeFromPayload(data.actionName, data.payload).then((status) => { - if (status) { - return res.end('ok'); - } + getPostJSONRequestData(req, res) + .then((data) => + executeFromPayload(data.actionName, data.payload).then((status) => { + if (status) { + return res.end('ok'); + } + res.statusCode = 500; + res.end('Error executing command'); + }), + ) + .catch((error) => { + Logger.error('Error executing command', error); res.statusCode = 500; res.end('Error executing command'); - }), - ); + }); break; } From 9ea214d523bbef6b4e97a775a125ab1ae60bc53c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 27 Oct 2023 13:31:14 +0200 Subject: [PATCH 20/30] fix warnings thrown --- src/libs/E2E/client.js | 4 ++-- tests/e2e/server/index.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/E2E/client.js b/src/libs/E2E/client.js index 0da87094683a..56447fd09133 100644 --- a/src/libs/E2E/client.js +++ b/src/libs/E2E/client.js @@ -58,10 +58,10 @@ const sendNativeCommand = (payload) => }, body: JSON.stringify(payload), }).then((res) => { - if (res.statusCode === 200) { + if (res.status === 200) { return true; } - const errorMsg = `Sending native command failed with status code ${res.statusCode}`; + const errorMsg = `Sending native command failed with status code ${res.status}`; res.json() .then((responseText) => { throw new Error(`${errorMsg}: ${responseText}`); diff --git a/tests/e2e/server/index.js b/tests/e2e/server/index.js index 51a227ed1c33..4c2e00126fd5 100644 --- a/tests/e2e/server/index.js +++ b/tests/e2e/server/index.js @@ -131,7 +131,8 @@ const createServerInstance = () => { .then((data) => executeFromPayload(data.actionName, data.payload).then((status) => { if (status) { - return res.end('ok'); + res.end('ok'); + return; } res.statusCode = 500; res.end('Error executing command'); From 31b677e5b660c07c0b5db668a4dcd4b34e4d4e1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 27 Oct 2023 13:41:16 +0200 Subject: [PATCH 21/30] remove unused native ID --- .../ComposerWithSuggestions/ComposerWithSuggestions.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js index 6f885f8c6009..1bc6688a9db5 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js @@ -524,10 +524,7 @@ function ComposerWithSuggestions({ return ( <> - + Date: Fri, 27 Oct 2023 14:12:23 +0200 Subject: [PATCH 22/30] add index file --- .../ReportActionCompose/ComposerWithSuggestions/index.js | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.js diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.js new file mode 100644 index 000000000000..f2aebd390ba6 --- /dev/null +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.js @@ -0,0 +1,3 @@ +import ComposerWithSuggestions from './ComposerWithSuggestions'; + +export default ComposerWithSuggestions; From e01cf4f5515808967146faab54613ad7a822ac61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 27 Oct 2023 14:14:12 +0200 Subject: [PATCH 23/30] add test --- src/libs/E2E/reactNativeLaunchingTest.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/E2E/reactNativeLaunchingTest.js b/src/libs/E2E/reactNativeLaunchingTest.js index 13183c1044db..a2c8ba3aec31 100644 --- a/src/libs/E2E/reactNativeLaunchingTest.js +++ b/src/libs/E2E/reactNativeLaunchingTest.js @@ -24,6 +24,7 @@ if (!Metrics.canCapturePerformanceMetrics()) { const tests = { [E2EConfig.TEST_NAMES.AppStartTime]: require('./tests/appStartTimeTest.e2e').default, [E2EConfig.TEST_NAMES.OpenSearchPage]: require('./tests/openSearchPageTest.e2e').default, + [E2EConfig.TEST_NAMES.ReportTyping]: require('./tests/reportTypingTest.e2e').default, }; // Once we receive the TII measurement we know that the app is initialized and ready to be used: From eda60a37d8b7c1989e1068db59caf2febb1569e5 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Fri, 27 Oct 2023 14:35:12 +0200 Subject: [PATCH 24/30] create chat opening test --- src/libs/E2E/reactNativeLaunchingTest.js | 3 +- src/libs/E2E/tests/chatOpeningTest.e2e.js | 50 +++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/libs/E2E/tests/chatOpeningTest.e2e.js diff --git a/src/libs/E2E/reactNativeLaunchingTest.js b/src/libs/E2E/reactNativeLaunchingTest.js index 13183c1044db..1e923e75aea2 100644 --- a/src/libs/E2E/reactNativeLaunchingTest.js +++ b/src/libs/E2E/reactNativeLaunchingTest.js @@ -24,6 +24,7 @@ if (!Metrics.canCapturePerformanceMetrics()) { const tests = { [E2EConfig.TEST_NAMES.AppStartTime]: require('./tests/appStartTimeTest.e2e').default, [E2EConfig.TEST_NAMES.OpenSearchPage]: require('./tests/openSearchPageTest.e2e').default, + [E2EConfig.TEST_NAMES.ChatOpening]: require('./tests/chatOpeningTest.e2e').default, }; // Once we receive the TII measurement we know that the app is initialized and ready to be used: @@ -65,5 +66,5 @@ E2EClient.getTestConfig() // start the usual app Performance.markStart('regularAppStart'); -import '../../../index'; +import '../../../appIndex'; Performance.markEnd('regularAppStart'); diff --git a/src/libs/E2E/tests/chatOpeningTest.e2e.js b/src/libs/E2E/tests/chatOpeningTest.e2e.js new file mode 100644 index 000000000000..f5c25add4812 --- /dev/null +++ b/src/libs/E2E/tests/chatOpeningTest.e2e.js @@ -0,0 +1,50 @@ +import E2ELogin from '../actions/e2eLogin'; +import Performance from '../../Performance'; +import E2EClient from '../client'; +import Navigation from '../../Navigation/Navigation'; +import ROUTES from '../../../ROUTES'; +import CONST from '../../../CONST'; +import getReport from '../apiMocks/openReport'; + +const test = () => { + // check for login (if already logged in the action will simply resolve) + console.debug('[E2E] Logging in for chat opening'); + const report = getReport(); + const reportID = report.onyxData[0].value.reportID; + + E2ELogin().then((neededLogin) => { + if (neededLogin) { + // we don't want to submit the first login to the results + return E2EClient.submitTestDone(); + } + + console.debug('[E2E] Logged in, getting chat opening metrics and submitting them…'); + + Performance.subscribeToMeasurements((entry) => { + if (entry.name === CONST.TIMING.SIDEBAR_LOADED) { + console.debug(`[E2E] Sidebar loaded, navigating to search route…`); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(reportID)); + return; + } + console.debug(`[E2E] Entry: ${JSON.stringify(entry)}`); + if (entry.name !== CONST.TIMING.CHAT_RENDER) { + return; + } + + console.debug(`[E2E] Submitting!`); + E2EClient.submitTestResults({ + name: 'Chat opening', + duration: entry.duration, + }) + .then(() => { + console.debug('[E2E] Done with search, exiting…'); + E2EClient.submitTestDone(); + }) + .catch((err) => { + console.debug('[E2E] Error while submitting test results:', err); + }); + }); + }); +}; + +export default test; From 79e06210f191f0452c1345b0018fdb8b6100b268 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Fri, 27 Oct 2023 14:35:54 +0200 Subject: [PATCH 25/30] add timers --- src/CONST.ts | 1 + src/pages/home/ReportScreen.js | 11 ++++++++++- src/pages/home/report/ReportActionsList.js | 4 ++++ tests/e2e/config.js | 4 ++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index a6106b88a532..1388b95162d9 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -678,6 +678,7 @@ const CONST = { TIMING: { CALCULATE_MOST_RECENT_LAST_MODIFIED_ACTION: 'calc_most_recent_last_modified_action', SEARCH_RENDER: 'search_render', + CHAT_RENDER: 'chat_render', HOMEPAGE_INITIAL_RENDER: 'homepage_initial_render', REPORT_INITIAL_RENDER: 'report_initial_render', SWITCH_REPORT: 'switch_report', diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 32a14303e9a7..3ec76c6c30a4 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -10,8 +10,11 @@ import ScreenWrapper from '../../components/ScreenWrapper'; import HeaderView from './HeaderView'; import Navigation from '../../libs/Navigation/Navigation'; import ROUTES from '../../ROUTES'; -import * as Report from '../../libs/actions/Report'; import ONYXKEYS from '../../ONYXKEYS'; +import PAGES_CONST from '../PAGES_CONST'; +import Timing from '../../libs/actions/Timing'; +import Performance from '../../libs/Performance'; +import * as Report from '../../libs/actions/Report'; import * as ReportUtils from '../../libs/ReportUtils'; import ReportActionsView from './report/ReportActionsView'; import ReportActionsSkeletonView from '../../components/ReportActionsSkeletonView'; @@ -160,6 +163,11 @@ function ReportScreen({ const [isBannerVisible, setIsBannerVisible] = useState(true); const [listHeight, setListHeight] = useState(0); + if (firstRenderRef.current) { + Timing.start(CONST.TIMING.CHAT_RENDER); + Performance.markStart(CONST.TIMING.CHAT_RENDER); + } + const reportID = getReportID(route); const {addWorkspaceRoomOrChatPendingAction, addWorkspaceRoomOrChatErrors} = ReportUtils.getReportOfflinePendingActionAndErrors(report); const screenWrapperStyle = [styles.appContent, styles.flex1, {marginTop: viewportOffsetTop}]; @@ -468,6 +476,7 @@ ReportScreen.defaultProps = defaultProps; ReportScreen.displayName = 'ReportScreen'; export default compose( + Performance.withRenderTrace({id: PAGES_CONST.REPORT_ACTIONS_VIEW}), withViewportOffsetTop, withCurrentReportID, withOnyx( diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 3cdd8ece876f..469a175b978d 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -16,6 +16,8 @@ import useReportScrollManager from '../../../hooks/useReportScrollManager'; import DateUtils from '../../../libs/DateUtils'; import * as ReportUtils from '../../../libs/ReportUtils'; import * as Report from '../../../libs/actions/Report'; +import Performance from '../../../libs/Performance'; +import Timing from '../../../libs/actions/Timing'; import compose from '../../../libs/compose'; import styles from '../../../styles/styles'; import variables from '../../../styles/variables'; @@ -368,6 +370,8 @@ function ReportActionsList({ const onLayoutInner = useCallback( (event) => { onLayout(event); + Timing.end(CONST.TIMING.CHAT_RENDER); + Performance.markEnd(CONST.TIMING.CHAT_RENDER); }, [onLayout], ); diff --git a/tests/e2e/config.js b/tests/e2e/config.js index 6095927d0174..5b93bfbd38ec 100644 --- a/tests/e2e/config.js +++ b/tests/e2e/config.js @@ -10,6 +10,7 @@ const TEST_NAMES = { AppStartTime: 'App start time', OpenSearchPage: 'Open search page TTI', ReportTyping: 'Report typing', + ChatOpening: 'Chat opening', }; /** @@ -70,5 +71,8 @@ module.exports = { autoFocus: true, }, }, + [TEST_NAMES.ChatOpening]: { + name: TEST_NAMES.ChatOpening, + }, }, }; From 8b5a3e3b3ebbc6a89336df20b99a12a851c24b8a Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Fri, 27 Oct 2023 15:11:48 +0200 Subject: [PATCH 26/30] remove PAGES_CONST --- src/pages/home/ReportScreen.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 3ec76c6c30a4..3b4bf3d3e761 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -11,7 +11,6 @@ import HeaderView from './HeaderView'; import Navigation from '../../libs/Navigation/Navigation'; import ROUTES from '../../ROUTES'; import ONYXKEYS from '../../ONYXKEYS'; -import PAGES_CONST from '../PAGES_CONST'; import Timing from '../../libs/actions/Timing'; import Performance from '../../libs/Performance'; import * as Report from '../../libs/actions/Report'; @@ -476,7 +475,6 @@ ReportScreen.defaultProps = defaultProps; ReportScreen.displayName = 'ReportScreen'; export default compose( - Performance.withRenderTrace({id: PAGES_CONST.REPORT_ACTIONS_VIEW}), withViewportOffsetTop, withCurrentReportID, withOnyx( From d3d21026e084423cfcb29acd29c664f29e6fb4c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 30 Oct 2023 09:50:06 +0100 Subject: [PATCH 27/30] fix e2e tests after eslint/prettier import changes --- .prettierignore | 2 ++ src/libs/E2E/reactNativeLaunchingTest.js | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.prettierignore b/.prettierignore index 5f6292b551c1..80888b18a317 100644 --- a/.prettierignore +++ b/.prettierignore @@ -15,3 +15,5 @@ package-lock.json *.css *.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 diff --git a/src/libs/E2E/reactNativeLaunchingTest.js b/src/libs/E2E/reactNativeLaunchingTest.js index 13a1db1d499c..f9ff4383f86d 100644 --- a/src/libs/E2E/reactNativeLaunchingTest.js +++ b/src/libs/E2E/reactNativeLaunchingTest.js @@ -7,7 +7,6 @@ */ import * as Metrics from '@libs/Metrics'; import Performance from '@libs/Performance'; -import '../../../index'; import E2EConfig from '../../../tests/e2e/config'; import E2EClient from './client'; @@ -66,5 +65,5 @@ E2EClient.getTestConfig() // start the usual app Performance.markStart('regularAppStart'); - +import '../../../index'; Performance.markEnd('regularAppStart'); From 347d2a7bf17e42dddafced4c8efe9afd8f70f9c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 30 Oct 2023 10:00:53 +0100 Subject: [PATCH 28/30] fix eslint warnings --- src/libs/E2E/tests/reportTypingTest.e2e.js | 16 ++++++++-------- .../ComposerWithSuggestions/index.e2e.js | 9 ++++++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/libs/E2E/tests/reportTypingTest.e2e.js b/src/libs/E2E/tests/reportTypingTest.e2e.js index ec2ddbea013c..b79166063b4f 100644 --- a/src/libs/E2E/tests/reportTypingTest.e2e.js +++ b/src/libs/E2E/tests/reportTypingTest.e2e.js @@ -1,12 +1,12 @@ -import E2ELogin from '../actions/e2eLogin'; -import Performance from '../../Performance'; -import E2EClient from '../client'; -import Navigation from '../../Navigation/Navigation'; -import ROUTES from '../../../ROUTES'; -import CONST from '../../../CONST'; +import E2ELogin from '@libs/E2E/actions/e2eLogin'; +import waitForKeyboard from '@libs/E2E/actions/waitForKeyboard'; +import E2EClient from '@libs/E2E/client'; +import Navigation from '@libs/Navigation/Navigation'; +import Performance from '@libs/Performance'; +import {getRerenderCount, resetRerenderCount} from '@pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; import * as NativeCommands from '../../../../tests/e2e/nativeCommands/NativeCommandsAction'; -import waitForKeyboard from '../actions/waitForKeyboard'; -import {resetRerenderCount, getRerenderCount} from '../../../pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e'; const test = () => { // check for login (if already logged in the action will simply resolve) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.js index ab626ac0f2e8..cbbd1758c9cb 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.js @@ -1,7 +1,7 @@ -import React, {useEffect} from 'react'; import _ from 'lodash'; +import React, {useEffect} from 'react'; +import E2EClient from '@libs/E2E/client'; import ComposerWithSuggestions from './ComposerWithSuggestions'; -import E2EClient from '../../../../../libs/E2E/client'; let rerenderCount = 0; const getRerenderCount = () => rerenderCount; @@ -14,7 +14,7 @@ function IncrementRenderCount() { return null; } -export default React.forwardRef((props, ref) => { +const ComposerWithSuggestionsE2e = React.forwardRef((props, ref) => { // Eventually Auto focus on e2e tests useEffect(() => { if (_.get(E2EClient.getCurrentActiveTestConfig(), 'reportScreen.autoFocus', false) === false) { @@ -46,4 +46,7 @@ export default React.forwardRef((props, ref) => { ); }); +ComposerWithSuggestionsE2e.displayName = 'ComposerWithSuggestionsE2e'; + +export default ComposerWithSuggestionsE2e; export {getRerenderCount, resetRerenderCount}; From d486d32c4267da8bffbdb91e964c0c3304b1dec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 30 Oct 2023 10:12:18 +0100 Subject: [PATCH 29/30] fix imports --- .../ComposerWithSuggestions/ComposerWithSuggestions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js index 576267b80011..fe8fec187da7 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js @@ -25,6 +25,8 @@ import * as ReportUtils from '@libs/ReportUtils'; import * as SuggestionUtils from '@libs/SuggestionUtils'; import updateMultilineInputRange from '@libs/UpdateMultilineInputRange'; import willBlurTextInputOnTapOutsideFunc from '@libs/willBlurTextInputOnTapOutside'; +import SilentCommentUpdater from '@pages/home/report/ReportActionCompose/SilentCommentUpdater'; +import Suggestions from '@pages/home/report/ReportActionCompose/Suggestions'; import containerComposeStyles from '@styles/containerComposeStyles'; import styles from '@styles/styles'; import themeColors from '@styles/themes/default'; @@ -35,8 +37,6 @@ import * as User from '@userActions/User'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {defaultProps, propTypes} from './composerWithSuggestionsProps'; -import SilentCommentUpdater from './SilentCommentUpdater'; -import Suggestions from './Suggestions'; const {RNTextInputReset} = NativeModules; From d2c6d8e9a37e381db74aff4e3cba04111349212b Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Tue, 31 Oct 2023 13:36:01 +0100 Subject: [PATCH 30/30] end timing in ReportScreen --- src/libs/E2E/tests/chatOpeningTest.e2e.js | 63 +++++++++++----------- src/pages/home/ReportScreen.js | 7 ++- src/pages/home/report/ReportActionsList.js | 4 -- 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/src/libs/E2E/tests/chatOpeningTest.e2e.js b/src/libs/E2E/tests/chatOpeningTest.e2e.js index f5c25add4812..3fadbe333c9b 100644 --- a/src/libs/E2E/tests/chatOpeningTest.e2e.js +++ b/src/libs/E2E/tests/chatOpeningTest.e2e.js @@ -1,10 +1,11 @@ -import E2ELogin from '../actions/e2eLogin'; -import Performance from '../../Performance'; -import E2EClient from '../client'; -import Navigation from '../../Navigation/Navigation'; -import ROUTES from '../../../ROUTES'; -import CONST from '../../../CONST'; -import getReport from '../apiMocks/openReport'; +import E2ECleanReportActions from '@libs/E2E/actions/cleanReportActions'; +import E2ELogin from '@libs/E2E/actions/e2eLogin'; +import getReport from '@libs/E2E/apiMocks/openReport'; +import E2EClient from '@libs/E2E/client'; +import Navigation from '@libs/Navigation/Navigation'; +import Performance from '@libs/Performance'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; const test = () => { // check for login (if already logged in the action will simply resolve) @@ -18,31 +19,33 @@ const test = () => { return E2EClient.submitTestDone(); } - console.debug('[E2E] Logged in, getting chat opening metrics and submitting them…'); + console.debug('[E2E] Logged in, cleaning report actions from onyx…'); + E2ECleanReportActions().then(() => { + console.debug('[E2E] Logged in, getting chat opening metrics and submitting them…'); + Performance.subscribeToMeasurements((entry) => { + if (entry.name === CONST.TIMING.SIDEBAR_LOADED) { + console.debug(`[E2E] Sidebar loaded, navigating to search route…`); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(reportID)); + return; + } + console.debug(`[E2E] Entry: ${JSON.stringify(entry)}`); + if (entry.name !== CONST.TIMING.CHAT_RENDER) { + return; + } - Performance.subscribeToMeasurements((entry) => { - if (entry.name === CONST.TIMING.SIDEBAR_LOADED) { - console.debug(`[E2E] Sidebar loaded, navigating to search route…`); - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(reportID)); - return; - } - console.debug(`[E2E] Entry: ${JSON.stringify(entry)}`); - if (entry.name !== CONST.TIMING.CHAT_RENDER) { - return; - } - - console.debug(`[E2E] Submitting!`); - E2EClient.submitTestResults({ - name: 'Chat opening', - duration: entry.duration, - }) - .then(() => { - console.debug('[E2E] Done with search, exiting…'); - E2EClient.submitTestDone(); + console.debug(`[E2E] Submitting!`); + E2EClient.submitTestResults({ + name: 'Chat opening', + duration: entry.duration, }) - .catch((err) => { - console.debug('[E2E] Error while submitting test results:', err); - }); + .then(() => { + console.debug('[E2E] Done with search, exiting…'); + E2EClient.submitTestDone(); + }) + .catch((err) => { + console.debug('[E2E] Error while submitting test results:', err); + }); + }); }); }); }; diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index f4082f134ee3..2f89b89de553 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -19,10 +19,12 @@ import withViewportOffsetTop from '@components/withViewportOffsetTop'; import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; import useWindowDimensions from '@hooks/useWindowDimensions'; +import Timing from '@libs/actions/Timing'; import compose from '@libs/compose'; import getIsReportFullyVisible from '@libs/getIsReportFullyVisible'; import Navigation from '@libs/Navigation/Navigation'; import reportWithoutHasDraftSelector from '@libs/OnyxSelectors/reportWithoutHasDraftSelector'; +import Performance from '@libs/Performance'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import Visibility from '@libs/Visibility'; @@ -36,8 +38,6 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import HeaderView from './HeaderView'; -import Timing from '@libs/actions/Timing'; -import Performance from '@libs/Performance'; import reportActionPropTypes from './report/reportActionPropTypes'; import ReportActionsView from './report/ReportActionsView'; import ReportFooter from './report/ReportFooter'; @@ -303,6 +303,9 @@ function ReportScreen({ ); useEffect(() => { + Timing.end(CONST.TIMING.CHAT_RENDER); + Performance.markEnd(CONST.TIMING.CHAT_RENDER); + fetchReportIfNeeded(); ComposerActions.setShouldShowComposeInput(true); return () => { diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 7da0c70d0a11..8fa40a96bd6b 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -4,8 +4,6 @@ import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; import _ from 'underscore'; -import Performance from '@libs/Performance'; -import Timing from '@libs/actions/Timing'; import InvertedFlatList from '@components/InvertedFlatList'; import {withPersonalDetails} from '@components/OnyxProvider'; import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails'; @@ -387,8 +385,6 @@ function ReportActionsList({ const onLayoutInner = useCallback( (event) => { onLayout(event); - Timing.end(CONST.TIMING.CHAT_RENDER); - Performance.markEnd(CONST.TIMING.CHAT_RENDER); }, [onLayout], );