From 3e186f452eda5f12c30c54e8646b633fe0b9d23a Mon Sep 17 00:00:00 2001 From: tomholub Date: Fri, 3 Dec 2021 20:36:52 +0100 Subject: [PATCH 01/10] issue 1006 app to call FES mock --- FlowCrypt.xcodeproj/project.pbxproj | 12 ++++++++++ FlowCrypt/Extensions/BundleExtensions.swift | 24 +++++++++++++++++++ .../Extensions/CommandLineExtensions.swift | 20 ++++++++++++++++ .../EnterpriseServerApi.swift | 22 ++++++++++------- 4 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 FlowCrypt/Extensions/BundleExtensions.swift create mode 100644 FlowCrypt/Extensions/CommandLineExtensions.swift diff --git a/FlowCrypt.xcodeproj/project.pbxproj b/FlowCrypt.xcodeproj/project.pbxproj index 582741b2a..8361b6332 100644 --- a/FlowCrypt.xcodeproj/project.pbxproj +++ b/FlowCrypt.xcodeproj/project.pbxproj @@ -361,6 +361,10 @@ D2FD0F692453245E00259FF0 /* Either.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FD0F682453245E00259FF0 /* Either.swift */; }; D2FF6966243115EC007182F0 /* SetupImapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FF6965243115EC007182F0 /* SetupImapViewController.swift */; }; D2FF6968243115F9007182F0 /* SetupImapViewDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FF6967243115F9007182F0 /* SetupImapViewDecorator.swift */; }; + E26D5E1F275AA295007B8802 /* CommandLineExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26D5E1E275AA295007B8802 /* CommandLineExtensions.swift */; }; + E26D5E21275AA417007B8802 /* BundleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26D5E20275AA417007B8802 /* BundleExtensions.swift */; }; + E26D5E22275AA421007B8802 /* BundleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26D5E20275AA417007B8802 /* BundleExtensions.swift */; }; + E26D5E23275AA42B007B8802 /* CommandLineExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26D5E1E275AA295007B8802 /* CommandLineExtensions.swift */; }; F191F621272511790053833E /* BlurViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F191F620272511790053833E /* BlurViewController.swift */; }; F80E95362720B6640093F243 /* DraftsListProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80E95352720B6640093F243 /* DraftsListProvider.swift */; }; F8678DCC2722143300BB1710 /* GmailService+draft.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8678DCB2722143300BB1710 /* GmailService+draft.swift */; }; @@ -768,6 +772,8 @@ D2FF6965243115EC007182F0 /* SetupImapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupImapViewController.swift; sourceTree = ""; }; D2FF6967243115F9007182F0 /* SetupImapViewDecorator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupImapViewDecorator.swift; sourceTree = ""; }; D9381A4EE6BAAD97294A7F9A /* Pods-FlowCryptUI.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FlowCryptUI.release.xcconfig"; path = "Target Support Files/Pods-FlowCryptUI/Pods-FlowCryptUI.release.xcconfig"; sourceTree = ""; }; + E26D5E1E275AA295007B8802 /* CommandLineExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandLineExtensions.swift; sourceTree = ""; }; + E26D5E20275AA417007B8802 /* BundleExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleExtensions.swift; sourceTree = ""; }; F191F620272511790053833E /* BlurViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurViewController.swift; sourceTree = ""; }; F80E95352720B6640093F243 /* DraftsListProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftsListProvider.swift; sourceTree = ""; }; F8678DCB2722143300BB1710 /* GmailService+draft.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GmailService+draft.swift"; sourceTree = ""; }; @@ -1002,7 +1008,9 @@ isa = PBXGroup; children = ( D2D27B78248A8694007346FA /* BigIntExtension.swift */, + E26D5E20275AA417007B8802 /* BundleExtensions.swift */, 9F2F217226B3269D0044E144 /* CombineExtensions.swift */, + E26D5E1E275AA295007B8802 /* CommandLineExtensions.swift */, 51E4F0B427348E310017DABB /* Error+Extension.swift */, 51B0C7702729861C00124663 /* String+Extension.swift */, 518389C92726D8F700131B2C /* UIApplicationExtension.swift */, @@ -2476,6 +2484,7 @@ 9F976584267E194F0058419D /* TestData.swift in Sources */, 9F6F3C6A26ADFBEB005BD9C6 /* MessageGatewayMock.swift in Sources */, 9F7E903926A1AD7A0021C07F /* KeyDetailsTests.swift in Sources */, + E26D5E23275AA42B007B8802 /* CommandLineExtensions.swift in Sources */, 51B0C774272AB61000124663 /* StringTestExtension.swift in Sources */, 2C2A3B4B2719EE6100B7F27B /* KeyServiceTests.swift in Sources */, 9F976490267E11880058419D /* ImapHelperTest.swift in Sources */, @@ -2509,6 +2518,7 @@ 9F5F503526F90E5F00294FA2 /* ClientConfigurationServiceTests.swift in Sources */, 9F2F206826AEEAA60044E144 /* CombineTestExtension.swift in Sources */, 9F976585267E194F0058419D /* FlowCryptCoreTests.swift in Sources */, + E26D5E22275AA421007B8802 /* BundleExtensions.swift in Sources */, 9F6F3C7D26ADFC60005BD9C6 /* ContactsServiceMock.swift in Sources */, 9F6F3C3C26ADFBC7005BD9C6 /* CoreComposeMessageMock.swift in Sources */, 9FC4116B2681186D004C0A69 /* KeyMethodsTest.swift in Sources */, @@ -2670,6 +2680,7 @@ 9F9AAFFD2383E216000A00F1 /* Document.swift in Sources */, 9FE1B3A02565B0CE00D6D086 /* Message.swift in Sources */, D27177492424D73000BDA9A9 /* InboxViewDecorator.swift in Sources */, + E26D5E1F275AA295007B8802 /* CommandLineExtensions.swift in Sources */, D2F41371243CC76F0066AFB5 /* SessionRealmObject.swift in Sources */, 9F9362192573D10E0009912F /* Imap+Message.swift in Sources */, 32DCA9C61ABB3234649B374E /* CoreHost.swift in Sources */, @@ -2734,6 +2745,7 @@ 9F53CB872555E7F300C0157A /* Imap+Other.swift in Sources */, D2F6D1352433753B00DB4065 /* SMTPSession.swift in Sources */, 9FBEAF3125DFB8E1009E98D4 /* DBMigrationService.swift in Sources */, + E26D5E21275AA417007B8802 /* BundleExtensions.swift in Sources */, 9F17976D2368EEBD002BF770 /* SetupViewDecorator.swift in Sources */, 5ADEDCC023A43B0800EC495E /* KeyDetailInfoViewDecorator.swift in Sources */, D227C0E6250538780070F805 /* RemoteFoldersProvider.swift in Sources */, diff --git a/FlowCrypt/Extensions/BundleExtensions.swift b/FlowCrypt/Extensions/BundleExtensions.swift new file mode 100644 index 000000000..0a249741f --- /dev/null +++ b/FlowCrypt/Extensions/BundleExtensions.swift @@ -0,0 +1,24 @@ +// +// AppBundle.swift +// FlowCrypt +// +// Created by Tom on 03.12.2021 +// Copyright © 2017-present FlowCrypt a. s. All rights reserved. +// + +import Foundation + +enum FlowCryptBundleType: String { + case debug = "com.flowcrypt.as.ios.debug", + consumer = "com.flowcrypt.as.ios.consumer", + enterprise = "com.flowcrypt.as.ios.enterprise" +} + +extension Bundle { + + static var flowCryptBundleType: FlowCryptBundleType { + guard let bundleIdentifier = Bundle.main.bundleIdentifier else { return .debug } + return FlowCryptBundleType(rawValue: bundleIdentifier) ?? .debug + } + +} diff --git a/FlowCrypt/Extensions/CommandLineExtensions.swift b/FlowCrypt/Extensions/CommandLineExtensions.swift new file mode 100644 index 000000000..3bc85d4b1 --- /dev/null +++ b/FlowCrypt/Extensions/CommandLineExtensions.swift @@ -0,0 +1,20 @@ +// +// CommandLineExtensions.swift +// FlowCrypt +// +// Created by Tom on 03.12.2021 +// Copyright © 2017-present FlowCrypt a. s. All rights reserved. +// + + + +import Foundation + +extension CommandLine { + + static func isDebugBundleWithArgument(_ argument: String) -> Bool { + guard Bundle.flowCryptBundleType == .debug else { return false } + return CommandLine.arguments.contains(argument) + } + +} diff --git a/FlowCrypt/Functionality/Services/Account Server Services/EnterpriseServerApi.swift b/FlowCrypt/Functionality/Services/Account Server Services/EnterpriseServerApi.swift index 015d2d6e2..930ddc91a 100644 --- a/FlowCrypt/Functionality/Services/Account Server Services/EnterpriseServerApi.swift +++ b/FlowCrypt/Functionality/Services/Account Server Services/EnterpriseServerApi.swift @@ -32,7 +32,7 @@ extension EnterpriseServerApiError: LocalizedError { class EnterpriseServerApi: EnterpriseServerApiType { static let publicEmailProviderDomains = ["gmail.com", "googlemail.com", "outlook.com"] - + private enum Constants { /// 404 - Not Found static let getToleratedHTTPStatuses = [404] @@ -52,16 +52,23 @@ class EnterpriseServerApi: EnterpriseServerApiType { let clientConfiguration: RawClientConfiguration } + private func constructUrlBase(emailDomain: String) -> String { + guard !CommandLine.isDebugBundleWithArgument("--mock-fes-api") else { + return "https://localhost:8001/fes/\(emailDomain)" // mock + } + return "https://fes.\(emailDomain)" // live + } + func getActiveFesUrl(for email: String) async throws -> String? { do { guard let userDomain = email.recipientDomain, !EnterpriseServerApi.publicEmailProviderDomains.contains(userDomain) else { return nil } - let urlString = "https://fes.\(userDomain)/" + let urlBase = constructUrlBase(emailDomain: userDomain) let request = ApiCall.Request( apiName: Constants.apiName, - url: "\(urlString)api/", + url: "\(urlBase)/api/", timeout: Constants.getActiveFesTimeout, tolerateStatus: Constants.getToleratedHTTPStatuses ) @@ -77,7 +84,7 @@ class EnterpriseServerApi: EnterpriseServerApiType { return nil } - return urlString + return urlBase } catch { if let httpError = error as? HttpErr, let nsError = httpError.error as NSError?, @@ -93,16 +100,13 @@ class EnterpriseServerApi: EnterpriseServerApiType { throw EnterpriseServerApiError.emailFormat } - guard try await getActiveFesUrl(for: email) != nil else { + guard let fesUrl = try await getActiveFesUrl(for: email) else { return .empty } - if EnterpriseServerApi.publicEmailProviderDomains.contains(userDomain) { - return .empty - } let request = ApiCall.Request( apiName: Constants.apiName, - url: "https://fes.\(userDomain)/api/v1/client-configuration?domain=\(userDomain)" + url: "\(fesUrl)/api/v1/client-configuration?domain=\(userDomain)" ) let safeReponse = try await ApiCall.call(request) From 4b95aa34b8c69ccd945c2418fbcb21bc0836a0aa Mon Sep 17 00:00:00 2001 From: tomholub Date: Fri, 3 Dec 2021 21:16:02 +0100 Subject: [PATCH 02/10] wip add mock specs --- appium/config/wdio.ios.app.conf.js | 43 ---------- appium/config/wdio.live.conf.js | 37 ++++++++ appium/config/wdio.mock.conf.js | 29 +++++++ appium/config/wdio.shared.conf.js | 86 ++++++++++--------- appium/package.json | 13 ++- .../CheckComposeEmailAfterReopening.spec.ts | 4 +- .../SelectRecipientByName.spec.ts | 4 +- ...entWithExpiredAndRevokedPublicKeys.spec.ts | 4 +- ...ndEmailToRecipientWithoutPublicKey.spec.ts | 4 +- ...erPassPhraseSessionEndedAndTrashIt.spec.ts | 6 +- .../inbox/CheckAllEmailSignatureCases.spec.ts | 0 ...CheckEncryptedEmailAfterRestartApp.spec.ts | 0 .../CheckMessageProcessingErrors.spec.ts | 0 ...ckReplyAndForwardForEncryptedEmail.spec.ts | 0 .../inbox/ReadAttachmentEmail.spec.ts | 0 .../inbox/ReadEmailAfterRestartApp.spec.ts | 0 .../inbox/ReadKeyMismatchEmail.spec.ts | 0 .../{ => live}/inbox/ReadTextEmail.spec.ts | 0 .../tests/specs/live/login/GmailLogin.spec.ts | 22 +++++ .../CheckSettingsForLoggedUser.spec.ts | 0 appium/tests/specs/login/GmailLogin.spec.ts | 31 ------- ...ithInconsistentClientConfiguration.spec.ts | 18 ++++ 22 files changed, 169 insertions(+), 132 deletions(-) delete mode 100644 appium/config/wdio.ios.app.conf.js create mode 100644 appium/config/wdio.live.conf.js create mode 100644 appium/config/wdio.mock.conf.js rename appium/tests/specs/{ => live}/composeEmail/CheckComposeEmailAfterReopening.spec.ts (90%) rename appium/tests/specs/{ => live}/composeEmail/SelectRecipientByName.spec.ts (96%) rename appium/tests/specs/{ => live}/composeEmail/SendEmailToRecipientWithExpiredAndRevokedPublicKeys.spec.ts (94%) rename appium/tests/specs/{ => live}/composeEmail/SendEmailToRecipientWithoutPublicKey.spec.ts (91%) rename appium/tests/specs/{ => live}/composeEmail/SendEncryptedEmailAfterPassPhraseSessionEndedAndTrashIt.spec.ts (95%) rename appium/tests/specs/{ => live}/inbox/CheckAllEmailSignatureCases.spec.ts (100%) rename appium/tests/specs/{ => live}/inbox/CheckEncryptedEmailAfterRestartApp.spec.ts (100%) rename appium/tests/specs/{ => live}/inbox/CheckMessageProcessingErrors.spec.ts (100%) rename appium/tests/specs/{ => live}/inbox/CheckReplyAndForwardForEncryptedEmail.spec.ts (100%) rename appium/tests/specs/{ => live}/inbox/ReadAttachmentEmail.spec.ts (100%) rename appium/tests/specs/{ => live}/inbox/ReadEmailAfterRestartApp.spec.ts (100%) rename appium/tests/specs/{ => live}/inbox/ReadKeyMismatchEmail.spec.ts (100%) rename appium/tests/specs/{ => live}/inbox/ReadTextEmail.spec.ts (100%) create mode 100644 appium/tests/specs/live/login/GmailLogin.spec.ts rename appium/tests/specs/{ => live}/settings/CheckSettingsForLoggedUser.spec.ts (100%) delete mode 100644 appium/tests/specs/login/GmailLogin.spec.ts create mode 100644 appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts diff --git a/appium/config/wdio.ios.app.conf.js b/appium/config/wdio.ios.app.conf.js deleted file mode 100644 index 48199cd6c..000000000 --- a/appium/config/wdio.ios.app.conf.js +++ /dev/null @@ -1,43 +0,0 @@ -const { join } = require('path'); -const { config } = require('./wdio.shared.conf'); -const pathWdioConfig = require('path'); -require('dotenv').config({ path: pathWdioConfig.resolve(__dirname, '../.env') }); - -process.on('unhandledRejection', (reason, promise) => { - // without this, after lib update to v7, whole test suite may pass even if no tests ran successfully - console.error('Force-quitting node process because unhandled rejection at:', promise, 'reason:', reason); - process.exit(1); -}); - -config.suites = { - all: [ - './tests/specs/**/*.spec.ts' - ], - smoke: [ - './tests/specs/login/GmailLogin.spec.ts' - ], - settings: [ - './tests/specs/settings/*.spec.ts' - ], - inbox: [ - './tests/specs/inbox/*.spec.ts' - ] -}; - -config.capabilities = [ - { - platformName: 'iOS', - iosInstallPause: 5000, - deviceName: 'iPhone 13', - platformVersion: '15.0', - automationName: 'XCUITest', - app: join(process.cwd(), './FlowCrypt.app'), - newCommandTimeout: 10000, - wdaLaunchTimeout: 300000, - wdaConnectionTimeout: 600000, - wdaStartupRetries: 4, - wdaStartupRetryInterval: 120000 - }, -]; - -exports.config = config; diff --git a/appium/config/wdio.live.conf.js b/appium/config/wdio.live.conf.js new file mode 100644 index 000000000..322715687 --- /dev/null +++ b/appium/config/wdio.live.conf.js @@ -0,0 +1,37 @@ +const { join } = require('path'); +const { config } = require('./wdio.shared.conf'); +const pathWdioConfig = require('path'); +require('dotenv').config({ path: pathWdioConfig.resolve(__dirname, '../.env') }); + +config.suites = { + all: [ + './tests/specs/live/**/*.spec.ts' + ], + smoke: [ + './tests/specs/live/login/GmailLogin.spec.ts' + ], + settings: [ + './tests/specs/live/settings/*.spec.ts' + ], + inbox: [ + './tests/specs/live/inbox/*.spec.ts' + ] +}; + +config.capabilities = [ + { + platformName: 'iOS', + iosInstallPause: 5000, + deviceName: 'iPhone 13', + platformVersion: '15.0', + automationName: 'XCUITest', + app: join(process.cwd(), './FlowCrypt.app'), + newCommandTimeout: 10000, + wdaLaunchTimeout: 300000, + wdaConnectionTimeout: 600000, + wdaStartupRetries: 4, + wdaStartupRetryInterval: 120000 + }, +]; + +exports.config = config; diff --git a/appium/config/wdio.mock.conf.js b/appium/config/wdio.mock.conf.js new file mode 100644 index 000000000..553eb2ff5 --- /dev/null +++ b/appium/config/wdio.mock.conf.js @@ -0,0 +1,29 @@ +const { join } = require('path'); +const { config } = require('./wdio.shared.conf'); +const pathWdioConfig = require('path'); +require('dotenv').config({ path: pathWdioConfig.resolve(__dirname, '../.env') }); + +config.suites = { + all: [ + './tests/specs/mock/**/*.spec.ts' + ], +}; + +config.capabilities = [ + { + platformName: 'iOS', + iosInstallPause: 5000, + deviceName: 'iPhone 13', + platformVersion: '15.0', + automationName: 'XCUITest', + app: join(process.cwd(), './FlowCrypt.app'), + processArguments: { 'args': ['--mock-fes-api'] }, + newCommandTimeout: 10000, + wdaLaunchTimeout: 300000, + wdaConnectionTimeout: 600000, + wdaStartupRetries: 4, + wdaStartupRetryInterval: 120000, + }, +]; + +exports.config = config; diff --git a/appium/config/wdio.shared.conf.js b/appium/config/wdio.shared.conf.js index fbeadcf82..f12b8a0d5 100644 --- a/appium/config/wdio.shared.conf.js +++ b/appium/config/wdio.shared.conf.js @@ -1,48 +1,54 @@ const { join } = require('path'); const video = require('wdio-video-reporter'); +process.on('unhandledRejection', (reason, promise) => { + // without this, after lib update to v7, whole test suite may pass even if no tests ran successfully + console.error('Force-quitting node process because unhandled rejection at:', promise, 'reason:', reason); + process.exit(1); +}); + exports.config = { - runner: 'local', - framework: 'jasmine', - jasmineNodeOpts: { - defaultTimeoutInterval: 600000, - requires: ['ts-node/register', 'tsconfig-paths/register'] - }, - sync: true, - logLevel: 'silent', - deprecationWarnings: true, - bail: 0, - waitforTimeout: 15000, - connectionRetryTimeout: 90000, - connectionRetryCount: 3, - maxInstancesPerCapability: 1, - reporters: [ - 'spec', - [video, { - saveAllVideos: false, // If true, also saves videos for successful test cases - videoSlowdownMultiplier: 3, // Higher to get slower videos, lower for faster videos [Value 1-100] - videoRenderTimeout: 10, // Max seconds to wait for a video to finish rendering - outputDir: './video', - }] - ], - services: [ - ['appium', { - command : './node_modules/.bin/appium', - logPath : join(process.cwd(), './tmp') - }] - ], - port: 4723, - path: '/wd/hub', - specFileRetries: 1, - specFileRetriesDeferred: false, + runner: 'local', + framework: 'jasmine', + jasmineNodeOpts: { + defaultTimeoutInterval: 600000, + requires: ['ts-node/register', 'tsconfig-paths/register'] + }, + sync: true, + logLevel: 'silent', + deprecationWarnings: true, + bail: 0, + waitforTimeout: 15000, + connectionRetryTimeout: 90000, + connectionRetryCount: 3, + maxInstancesPerCapability: 1, + reporters: [ + 'spec', + [video, { + saveAllVideos: false, // If true, also saves videos for successful test cases + videoSlowdownMultiplier: 3, // Higher to get slower videos, lower for faster videos [Value 1-100] + videoRenderTimeout: 10, // Max seconds to wait for a video to finish rendering + outputDir: './video', + }] + ], + services: [ + ['appium', { + command: './node_modules/.bin/appium', + logPath: join(process.cwd(), './tmp') + }] + ], + port: 4723, + path: '/wd/hub', + specFileRetries: 1, + specFileRetriesDeferred: false, - afterTest: function (test, context, { error, result, duration, passed, retries }) { - if (error) { - const timestampNow = new Date().getTime().toString(); - const path = join(process.cwd(), './tmp'); - driver.saveScreenshot(`${path}/${timestampNow}.png`); - console.log("Screenshot of failed test was saved to " + path) - } + afterTest: function (test, context, { error, result, duration, passed, retries }) { + if (error) { + const timestampNow = new Date().getTime().toString(); + const path = join(process.cwd(), './tmp'); + driver.saveScreenshot(`${path}/${timestampNow}.png`); + console.log("Screenshot of failed test was saved to " + path) } + } }; diff --git a/appium/package.json b/appium/package.json index fd699df45..8d498445c 100644 --- a/appium/package.json +++ b/appium/package.json @@ -4,13 +4,12 @@ "description": "", "main": "index.js", "scripts": { - "only.test.smoke": "./node_modules/.bin/wdio ./config/wdio.ios.app.conf.js --suite smoke", - "only.test.settings": "./node_modules/.bin/wdio ./config/wdio.ios.app.conf.js --suite settings", - "only.test.all": "./node_modules/.bin/wdio ./config/wdio.ios.app.conf.js --suite all", - "only.test.inbox": "./node_modules/.bin/wdio ./config/wdio.ios.app.conf.js --suite inbox", - "only.test.filter": "./node_modules/.bin/wdio ./config/wdio.ios.app.conf.js --suite all --jasmineNodeOpts.grep", + "only.test.smoke": "./node_modules/.bin/wdio ./config/wdio.live.conf.js --suite smoke", + "only.test.all": "./node_modules/.bin/wdio ./config/wdio.live.conf.js --suite all", + "only.test.filter": "./node_modules/.bin/wdio ./config/wdio.live.conf.js --suite all --jasmineNodeOpts.grep", + "only.test.mock.all": "./node_modules/.bin/wdio ./config/wdio.mock.conf.js --suite all", + "only.test.mock.filter": "./node_modules/.bin/wdio ./config/wdio.mock.conf.js --suite all --jasmineNodeOpts.grep", "test": "npm run-script build.app && npm run-script only.test.all", - "build.app": "cd .. && bundle exec fastlane build", "lint": "cd .. && ./appium/node_modules/.bin/eslint appium/ --ext .ts" }, "author": "FlowCrypt a. s.", @@ -53,4 +52,4 @@ "wdio-video-reporter": "^3.1.3", "webdriverio": "7.16.4" } -} +} \ No newline at end of file diff --git a/appium/tests/specs/composeEmail/CheckComposeEmailAfterReopening.spec.ts b/appium/tests/specs/live/composeEmail/CheckComposeEmailAfterReopening.spec.ts similarity index 90% rename from appium/tests/specs/composeEmail/CheckComposeEmailAfterReopening.spec.ts rename to appium/tests/specs/live/composeEmail/CheckComposeEmailAfterReopening.spec.ts index cbb880551..593b0fa92 100644 --- a/appium/tests/specs/composeEmail/CheckComposeEmailAfterReopening.spec.ts +++ b/appium/tests/specs/live/composeEmail/CheckComposeEmailAfterReopening.spec.ts @@ -3,9 +3,9 @@ import { SetupKeyScreen, MailFolderScreen, NewMessageScreen -} from '../../screenobjects/all-screens'; +} from '../../../screenobjects/all-screens'; -import { CommonData } from '../../data'; +import { CommonData } from '../../../data'; describe('COMPOSE EMAIL: ', () => { diff --git a/appium/tests/specs/composeEmail/SelectRecipientByName.spec.ts b/appium/tests/specs/live/composeEmail/SelectRecipientByName.spec.ts similarity index 96% rename from appium/tests/specs/composeEmail/SelectRecipientByName.spec.ts rename to appium/tests/specs/live/composeEmail/SelectRecipientByName.spec.ts index 341288187..2c7608763 100644 --- a/appium/tests/specs/composeEmail/SelectRecipientByName.spec.ts +++ b/appium/tests/specs/live/composeEmail/SelectRecipientByName.spec.ts @@ -7,9 +7,9 @@ import { ContactPublicKeyScreen, SettingsScreen, MenuBarScreen -} from '../../screenobjects/all-screens'; +} from '../../../screenobjects/all-screens'; -import { CommonData } from '../../data'; +import { CommonData } from '../../../data'; describe('COMPOSE EMAIL: ', () => { diff --git a/appium/tests/specs/composeEmail/SendEmailToRecipientWithExpiredAndRevokedPublicKeys.spec.ts b/appium/tests/specs/live/composeEmail/SendEmailToRecipientWithExpiredAndRevokedPublicKeys.spec.ts similarity index 94% rename from appium/tests/specs/composeEmail/SendEmailToRecipientWithExpiredAndRevokedPublicKeys.spec.ts rename to appium/tests/specs/live/composeEmail/SendEmailToRecipientWithExpiredAndRevokedPublicKeys.spec.ts index 83bf1662c..f56db44f6 100644 --- a/appium/tests/specs/composeEmail/SendEmailToRecipientWithExpiredAndRevokedPublicKeys.spec.ts +++ b/appium/tests/specs/live/composeEmail/SendEmailToRecipientWithExpiredAndRevokedPublicKeys.spec.ts @@ -3,9 +3,9 @@ import { SetupKeyScreen, MailFolderScreen, NewMessageScreen -} from '../../screenobjects/all-screens'; +} from '../../../screenobjects/all-screens'; -import { CommonData } from '../../data'; +import { CommonData } from '../../../data'; describe('COMPOSE EMAIL: ', () => { diff --git a/appium/tests/specs/composeEmail/SendEmailToRecipientWithoutPublicKey.spec.ts b/appium/tests/specs/live/composeEmail/SendEmailToRecipientWithoutPublicKey.spec.ts similarity index 91% rename from appium/tests/specs/composeEmail/SendEmailToRecipientWithoutPublicKey.spec.ts rename to appium/tests/specs/live/composeEmail/SendEmailToRecipientWithoutPublicKey.spec.ts index 4b8602c03..57f51fa86 100644 --- a/appium/tests/specs/composeEmail/SendEmailToRecipientWithoutPublicKey.spec.ts +++ b/appium/tests/specs/live/composeEmail/SendEmailToRecipientWithoutPublicKey.spec.ts @@ -3,9 +3,9 @@ import { SetupKeyScreen, MailFolderScreen, NewMessageScreen -} from '../../screenobjects/all-screens'; +} from '../../../screenobjects/all-screens'; -import { CommonData } from '../../data'; +import { CommonData } from '../../../data'; describe('COMPOSE EMAIL: ', () => { diff --git a/appium/tests/specs/composeEmail/SendEncryptedEmailAfterPassPhraseSessionEndedAndTrashIt.spec.ts b/appium/tests/specs/live/composeEmail/SendEncryptedEmailAfterPassPhraseSessionEndedAndTrashIt.spec.ts similarity index 95% rename from appium/tests/specs/composeEmail/SendEncryptedEmailAfterPassPhraseSessionEndedAndTrashIt.spec.ts rename to appium/tests/specs/live/composeEmail/SendEncryptedEmailAfterPassPhraseSessionEndedAndTrashIt.spec.ts index ad1dcff7a..8d4143276 100644 --- a/appium/tests/specs/composeEmail/SendEncryptedEmailAfterPassPhraseSessionEndedAndTrashIt.spec.ts +++ b/appium/tests/specs/live/composeEmail/SendEncryptedEmailAfterPassPhraseSessionEndedAndTrashIt.spec.ts @@ -5,10 +5,10 @@ import { NewMessageScreen, EmailScreen, MenuBarScreen, -} from '../../screenobjects/all-screens'; +} from '../../../screenobjects/all-screens'; -import { CommonData } from '../../data'; -import DataHelper from "../../helpers/DataHelper"; +import { CommonData } from '../../../data'; +import DataHelper from "../../../helpers/DataHelper"; describe('COMPOSE EMAIL: ', () => { diff --git a/appium/tests/specs/inbox/CheckAllEmailSignatureCases.spec.ts b/appium/tests/specs/live/inbox/CheckAllEmailSignatureCases.spec.ts similarity index 100% rename from appium/tests/specs/inbox/CheckAllEmailSignatureCases.spec.ts rename to appium/tests/specs/live/inbox/CheckAllEmailSignatureCases.spec.ts diff --git a/appium/tests/specs/inbox/CheckEncryptedEmailAfterRestartApp.spec.ts b/appium/tests/specs/live/inbox/CheckEncryptedEmailAfterRestartApp.spec.ts similarity index 100% rename from appium/tests/specs/inbox/CheckEncryptedEmailAfterRestartApp.spec.ts rename to appium/tests/specs/live/inbox/CheckEncryptedEmailAfterRestartApp.spec.ts diff --git a/appium/tests/specs/inbox/CheckMessageProcessingErrors.spec.ts b/appium/tests/specs/live/inbox/CheckMessageProcessingErrors.spec.ts similarity index 100% rename from appium/tests/specs/inbox/CheckMessageProcessingErrors.spec.ts rename to appium/tests/specs/live/inbox/CheckMessageProcessingErrors.spec.ts diff --git a/appium/tests/specs/inbox/CheckReplyAndForwardForEncryptedEmail.spec.ts b/appium/tests/specs/live/inbox/CheckReplyAndForwardForEncryptedEmail.spec.ts similarity index 100% rename from appium/tests/specs/inbox/CheckReplyAndForwardForEncryptedEmail.spec.ts rename to appium/tests/specs/live/inbox/CheckReplyAndForwardForEncryptedEmail.spec.ts diff --git a/appium/tests/specs/inbox/ReadAttachmentEmail.spec.ts b/appium/tests/specs/live/inbox/ReadAttachmentEmail.spec.ts similarity index 100% rename from appium/tests/specs/inbox/ReadAttachmentEmail.spec.ts rename to appium/tests/specs/live/inbox/ReadAttachmentEmail.spec.ts diff --git a/appium/tests/specs/inbox/ReadEmailAfterRestartApp.spec.ts b/appium/tests/specs/live/inbox/ReadEmailAfterRestartApp.spec.ts similarity index 100% rename from appium/tests/specs/inbox/ReadEmailAfterRestartApp.spec.ts rename to appium/tests/specs/live/inbox/ReadEmailAfterRestartApp.spec.ts diff --git a/appium/tests/specs/inbox/ReadKeyMismatchEmail.spec.ts b/appium/tests/specs/live/inbox/ReadKeyMismatchEmail.spec.ts similarity index 100% rename from appium/tests/specs/inbox/ReadKeyMismatchEmail.spec.ts rename to appium/tests/specs/live/inbox/ReadKeyMismatchEmail.spec.ts diff --git a/appium/tests/specs/inbox/ReadTextEmail.spec.ts b/appium/tests/specs/live/inbox/ReadTextEmail.spec.ts similarity index 100% rename from appium/tests/specs/inbox/ReadTextEmail.spec.ts rename to appium/tests/specs/live/inbox/ReadTextEmail.spec.ts diff --git a/appium/tests/specs/live/login/GmailLogin.spec.ts b/appium/tests/specs/live/login/GmailLogin.spec.ts new file mode 100644 index 000000000..8304517bd --- /dev/null +++ b/appium/tests/specs/live/login/GmailLogin.spec.ts @@ -0,0 +1,22 @@ +import { + SplashScreen, + SetupKeyScreen, + MenuBarScreen, + MailFolderScreen +} from '../../../screenobjects/all-screens'; + + +describe('LOGIN: ', () => { + + it('user is able to login via gmail', async () => { + await SplashScreen.login(); + await SetupKeyScreen.setPassPhrase(); + await MailFolderScreen.checkInboxScreen(); + + await MenuBarScreen.clickMenuIcon(); + await MenuBarScreen.checkUserEmail(); + + await MenuBarScreen.clickLogout(); + await SplashScreen.checkLoginPage(); + }); +}); diff --git a/appium/tests/specs/settings/CheckSettingsForLoggedUser.spec.ts b/appium/tests/specs/live/settings/CheckSettingsForLoggedUser.spec.ts similarity index 100% rename from appium/tests/specs/settings/CheckSettingsForLoggedUser.spec.ts rename to appium/tests/specs/live/settings/CheckSettingsForLoggedUser.spec.ts diff --git a/appium/tests/specs/login/GmailLogin.spec.ts b/appium/tests/specs/login/GmailLogin.spec.ts deleted file mode 100644 index 539d7b5fb..000000000 --- a/appium/tests/specs/login/GmailLogin.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { MockApi } from 'api-mocks/mock'; -import { - SplashScreen, - SetupKeyScreen, - MenuBarScreen, - MailFolderScreen -} from '../../screenobjects/all-screens'; - - -describe('LOGIN: ', () => { - - it('user is able to login via gmail + test running mocks', async () => { - const mockApi = new MockApi(); - // testing MockApi integration. For now the mock api starts and stops, - // but it is not used by the app yet. App still communicates to - // live APIs until we finish the integration on app side. - mockApi.fesConfig = { clientConfiguration: { key_manager_url: 'INTENTIONAL BAD URL' } }; - await mockApi.withMockedApis(async () => { - - await SplashScreen.login(); - await SetupKeyScreen.setPassPhrase(); - await MailFolderScreen.checkInboxScreen(); - - await MenuBarScreen.clickMenuIcon(); - await MenuBarScreen.checkUserEmail(); - - await MenuBarScreen.clickLogout(); - await SplashScreen.checkLoginPage(); - }); - }); -}); diff --git a/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts b/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts new file mode 100644 index 000000000..1a569c7d9 --- /dev/null +++ b/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts @@ -0,0 +1,18 @@ +import { MockApi } from 'api-mocks/mock'; +import { + SplashScreen, + // SetupKeyScreen, +} from '../../../screenobjects/all-screens'; + + +describe('LOGIN: ', () => { + + it('app setup fails with bad EKM URL', async () => { + const mockApi = new MockApi(); + mockApi.fesConfig = { clientConfiguration: { key_manager_url: 'INTENTIONAL BAD URL' } }; + await mockApi.withMockedApis(async () => { + await SplashScreen.login(); + // todo - await modal + }); + }); +}); From 1a5fe6071f2922df8e03b0ce0770b8941c573e34 Mon Sep 17 00:00:00 2001 From: tomholub Date: Fri, 3 Dec 2021 21:39:41 +0100 Subject: [PATCH 03/10] update readme, fixes --- .semaphore/semaphore.yml | 3 ++- .../EnterpriseServerApi.swift | 2 +- appium/README.md | 16 +++++++++++----- appium/api-mocks/apis/fes/fes-endpoints.ts | 8 ++++---- ...lsWithInconsistentClientConfiguration.spec.ts | 5 ++++- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml index 01f313db4..f01f927d6 100644 --- a/.semaphore/semaphore.yml +++ b/.semaphore/semaphore.yml @@ -39,7 +39,8 @@ blocks: - ios-sim start --devicetypeid com.apple.CoreSimulator.SimDeviceType.iPhone-13 - bundle exec fastlane build && ls -la appium - cd appium && npm run-script lint - - npm run-script only.test.all + - npm run-script only.test.mock.all + - npm run-script only.test.live.all epilogue: always: commands: diff --git a/FlowCrypt/Functionality/Services/Account Server Services/EnterpriseServerApi.swift b/FlowCrypt/Functionality/Services/Account Server Services/EnterpriseServerApi.swift index 930ddc91a..ceadc05f2 100644 --- a/FlowCrypt/Functionality/Services/Account Server Services/EnterpriseServerApi.swift +++ b/FlowCrypt/Functionality/Services/Account Server Services/EnterpriseServerApi.swift @@ -54,7 +54,7 @@ class EnterpriseServerApi: EnterpriseServerApiType { private func constructUrlBase(emailDomain: String) -> String { guard !CommandLine.isDebugBundleWithArgument("--mock-fes-api") else { - return "https://localhost:8001/fes/\(emailDomain)" // mock + return "http://127.0.0.1:8001/fes" // mock } return "https://fes.\(emailDomain)" // live } diff --git a/appium/README.md b/appium/README.md index 90b8872ba..8334baed4 100644 --- a/appium/README.md +++ b/appium/README.md @@ -10,12 +10,18 @@ 6. `nvm install 16` - installs NodeJS 16 and sets it as default 7. `cd ~/git/flowcrypt-ios/appium && npm install` -## Run tests +## Building app for testing + +Run this in `flowcrypt-ios` folder: `bundle exec fastlane build`. This will produce folder `appium/FlowCrypt.app` that contains the built app. -Run this in `appium` folder. +## Run tests -`npm test` - build `FlowCrypt.app` and run all ui tests +Run these in `appium` folder. -`npm run-script only.test.all` - run all ui tests without building the `.app`. Use this if you already built the `.app` before, and now only want to change the UI test spec without rebuilding the app +Tests that use live APIs: +- `npm run-script only.test.live.all` - run all ui tests +- `npm run-script only.test.live.filter "user is able to view text email"` - run a particular ui test -`npm run-script only.test.filter "user is able to view text email"` - run a particular ui test without building `.app`, filtered by name +Tests that use mock APIs: +- `npm run-script only.test.mock.all` - run all ui tests against mocks +- `npm run-script only.test.mock.filter "app setup fails with bad EKM URL"` - run a particular ui test against mocks diff --git a/appium/api-mocks/apis/fes/fes-endpoints.ts b/appium/api-mocks/apis/fes/fes-endpoints.ts index 45707585f..26d9dc7d6 100644 --- a/appium/api-mocks/apis/fes/fes-endpoints.ts +++ b/appium/api-mocks/apis/fes/fes-endpoints.ts @@ -16,7 +16,7 @@ export const getMockFesEndpoints = ( } return { - '/api/': async ({ }, req) => { + '/fes/api/': async ({ }, req) => { throwIfNotGetMethod(req); return { "vendor": "Mock", @@ -26,18 +26,18 @@ export const getMockFesEndpoints = ( "apiVersion": 'v1', }; }, - '/api/v1/client-configuration': async ({ }, req) => { + '/fes/api/v1/client-configuration': async ({ }, req) => { throwIfNotGetMethod(req); return { clientConfiguration: fesConfig.clientConfiguration }; }, - '/api/v1/message/new-reply-token': async ({ }, req) => { + '/fes/api/v1/message/new-reply-token': async ({ }, req) => { if (req.method === 'POST') { authenticate(req); return { 'replyToken': 'mock-fes-reply-token' }; } throw new HttpClientErr('Not Found', 404); }, - '/api/v1/message': async ({ body }, req) => { + '/fes/api/v1/message': async ({ body }, req) => { // body is a mime-multipart string, we're doing a few smoke checks here without parsing it if (req.method === 'POST') { expectContains(body, '-----BEGIN PGP MESSAGE-----'); diff --git a/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts b/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts index 1a569c7d9..c37153c15 100644 --- a/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts +++ b/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts @@ -12,7 +12,10 @@ describe('LOGIN: ', () => { mockApi.fesConfig = { clientConfiguration: { key_manager_url: 'INTENTIONAL BAD URL' } }; await mockApi.withMockedApis(async () => { await SplashScreen.login(); - // todo - await modal + await browser.pause(10000); + // todo - currently this passes because we are not testing the desired result yet + // it logs in and shows a "network lost" but should be showing a more specific modal + // mock is not reached yet probably due to app security settings (plain http) }); }); }); From 2cf7576daebe842dd83d6bb18349eea745962f4a Mon Sep 17 00:00:00 2001 From: tomholub Date: Fri, 3 Dec 2021 22:45:24 +0100 Subject: [PATCH 04/10] fix appium tests --- .semaphore/semaphore.yml | 4 ++-- appium/README.md | 12 +++++------- appium/package.json | 9 ++++----- ...pFailsWithInconsistentClientConfiguration.spec.ts | 2 +- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml index f01f927d6..7f3d79bb9 100644 --- a/.semaphore/semaphore.yml +++ b/.semaphore/semaphore.yml @@ -39,8 +39,8 @@ blocks: - ios-sim start --devicetypeid com.apple.CoreSimulator.SimDeviceType.iPhone-13 - bundle exec fastlane build && ls -la appium - cd appium && npm run-script lint - - npm run-script only.test.mock.all - - npm run-script only.test.live.all + - npm run-script test.mock.all + - npm run-script test.live.all epilogue: always: commands: diff --git a/appium/README.md b/appium/README.md index 8334baed4..d3fc8eaf9 100644 --- a/appium/README.md +++ b/appium/README.md @@ -16,12 +16,10 @@ Run this in `flowcrypt-ios` folder: `bundle exec fastlane build`. This will prod ## Run tests -Run these in `appium` folder. +Run these in `appium` folder. `live` means real production APIs, `mock` means local mock APIs. -Tests that use live APIs: -- `npm run-script only.test.live.all` - run all ui tests -- `npm run-script only.test.live.filter "user is able to view text email"` - run a particular ui test +To run a particular test: +- `npm run-script test.live "user is able to view text email"` +- `npm run-script test.mock "app setup fails with bad EKM URL"` -Tests that use mock APIs: -- `npm run-script only.test.mock.all` - run all ui tests against mocks -- `npm run-script only.test.mock.filter "app setup fails with bad EKM URL"` - run a particular ui test against mocks +To run all tests: `npm run-script test.live.all` or `npm run-script test.mock.all` \ No newline at end of file diff --git a/appium/package.json b/appium/package.json index 8d498445c..f0b612fb2 100644 --- a/appium/package.json +++ b/appium/package.json @@ -4,11 +4,10 @@ "description": "", "main": "index.js", "scripts": { - "only.test.smoke": "./node_modules/.bin/wdio ./config/wdio.live.conf.js --suite smoke", - "only.test.all": "./node_modules/.bin/wdio ./config/wdio.live.conf.js --suite all", - "only.test.filter": "./node_modules/.bin/wdio ./config/wdio.live.conf.js --suite all --jasmineNodeOpts.grep", - "only.test.mock.all": "./node_modules/.bin/wdio ./config/wdio.mock.conf.js --suite all", - "only.test.mock.filter": "./node_modules/.bin/wdio ./config/wdio.mock.conf.js --suite all --jasmineNodeOpts.grep", + "test.live.all": "./node_modules/.bin/wdio ./config/wdio.live.conf.js --suite all", + "test.live": "./node_modules/.bin/wdio ./config/wdio.live.conf.js --suite all --jasmineNodeOpts.grep", + "test.mock.all": "./node_modules/.bin/wdio ./config/wdio.mock.conf.js --suite all", + "test.mock": "./node_modules/.bin/wdio ./config/wdio.mock.conf.js --suite all --jasmineNodeOpts.grep", "test": "npm run-script build.app && npm run-script only.test.all", "lint": "cd .. && ./appium/node_modules/.bin/eslint appium/ --ext .ts" }, diff --git a/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts b/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts index c37153c15..4a7acfa12 100644 --- a/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts +++ b/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts @@ -12,7 +12,7 @@ describe('LOGIN: ', () => { mockApi.fesConfig = { clientConfiguration: { key_manager_url: 'INTENTIONAL BAD URL' } }; await mockApi.withMockedApis(async () => { await SplashScreen.login(); - await browser.pause(10000); + await browser.pause(30000); // todo - currently this passes because we are not testing the desired result yet // it logs in and shows a "network lost" but should be showing a more specific modal // mock is not reached yet probably due to app security settings (plain http) From 5649ea665815ecbb96f3deb71eac2c2cf3831f89 Mon Sep 17 00:00:00 2001 From: tomholub Date: Sat, 4 Dec 2021 11:04:28 +0100 Subject: [PATCH 05/10] fix mock tests --- .../apis/attester/attester-endpoints.ts | 27 +++++-- appium/api-mocks/apis/ekm/ekm-endpoints.ts | 22 ++++-- appium/api-mocks/apis/fes/fes-endpoints.ts | 27 ++++++- .../api-mocks/apis/google/google-endpoints.ts | 74 ++++++++++--------- .../strategies/send-message-strategy.ts | 48 ++++++------ appium/api-mocks/apis/wkd/wkd-endpoints.ts | 12 ++- appium/api-mocks/lib/api.ts | 42 +++++++---- appium/api-mocks/lib/configuration-types.ts | 18 ++++- appium/api-mocks/lib/mock-util.ts | 4 +- appium/api-mocks/lib/oauth.ts | 14 ++-- appium/api-mocks/mock.ts | 2 +- ...ithInconsistentClientConfiguration.spec.ts | 20 ++++- 12 files changed, 202 insertions(+), 108 deletions(-) diff --git a/appium/api-mocks/apis/attester/attester-endpoints.ts b/appium/api-mocks/apis/attester/attester-endpoints.ts index a31c3c596..61a0f67b4 100644 --- a/appium/api-mocks/apis/attester/attester-endpoints.ts +++ b/appium/api-mocks/apis/attester/attester-endpoints.ts @@ -1,11 +1,22 @@ /* ©️ 2016 - present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com */ -import { HandlersDefinition, HttpClientErr } from '../../lib/api'; +import { HandlersDefinition, HttpErr, Status } from '../../lib/api'; import { Dict } from '../../core/common'; import { isPost, isGet } from '../../lib/mock-util'; import { oauth } from '../../lib/oauth'; import { AttesterConfig, MockConfig } from '../../lib/configuration-types'; +export class AttesterErr extends HttpErr { + public formatted = (): unknown => { + return { // follows Attester errror format + error: { + "code": this.statusCode, + "message": this.message, + } + } + } +} + export const MOCK_ATTESTER_LAST_INSERTED_PUB: { [email: string]: string } = {}; export const getMockAttesterEndpoints = ( @@ -25,31 +36,31 @@ export const getMockAttesterEndpoints = ( if (pubkey) { return pubkey; } - throw new HttpClientErr('Pubkey not found on mock', 404); + throw new AttesterErr('Pubkey not found on mock', 404); } else if (isPost(req)) { if (attesterConfig.enableSubmittingPubkeys !== true) { - throw new HttpClientErr('Mock Attester received unexpected pubkey submission', 405); + throw new AttesterErr('Mock Attester received unexpected pubkey submission', 405); } oauth.checkAuthorizationHeaderWithIdToken(req.headers.authorization); if (!(body as string).includes('-----BEGIN PGP PUBLIC KEY BLOCK-----')) { - throw new HttpClientErr(`Bad public key format`, 400); + throw new AttesterErr(`Bad public key format`, 400); } MOCK_ATTESTER_LAST_INSERTED_PUB[email] = body as string; return 'Saved'; // 200 OK } else { - throw new HttpClientErr(`Not implemented: ${req.method}`); + throw new AttesterErr(`Not implemented: ${req.method}`, Status.BAD_REQUEST); } }, '/attester/test/welcome': async ({ body }, req) => { if (!isPost(req)) { - throw new HttpClientErr(`Wrong method: ${req.method}`); + throw new AttesterErr(`Wrong method: ${req.method}`, Status.BAD_REQUEST); } const { email, pubkey } = body as Dict; if (email.includes('@')) { - throw new HttpClientErr(`Bad email format`, 400); + throw new AttesterErr(`Bad email format`, 400); } if (pubkey.includes('-----BEGIN PGP PUBLIC KEY BLOCK-----')) { - throw new HttpClientErr(`Bad public key format`, 400); + throw new AttesterErr(`Bad public key format`, 400); } return { sent: true }; }, diff --git a/appium/api-mocks/apis/ekm/ekm-endpoints.ts b/appium/api-mocks/apis/ekm/ekm-endpoints.ts index 607d44b4e..85ad00c19 100644 --- a/appium/api-mocks/apis/ekm/ekm-endpoints.ts +++ b/appium/api-mocks/apis/ekm/ekm-endpoints.ts @@ -1,13 +1,13 @@ /* ©️ 2016 - present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com */ -// import { HttpClientErr } from '../lib/api'; +// import { HttpErr } from '../lib/api'; // import { isPut, isGet } from '../lib/mock-util'; // import { oauth } from '../lib/oauth'; // import { Dict } from '../../core/common'; // import { expect } from 'chai'; // import { KeyUtil } from '../../core/crypto/key'; // import { testConstants } from '../../tests/tooling/consts'; -import { HandlersDefinition } from '../../lib/api'; +import { HandlersDefinition, HttpErr } from '../../lib/api'; import { EkmConfig, MockConfig } from '../../lib/configuration-types'; // tslint:disable:max-line-length @@ -15,6 +15,16 @@ import { EkmConfig, MockConfig } from '../../lib/configuration-types'; // tslint:disable:no-unused-expression /* eslint-disable no-unused-expressions */ +export class EkmHttpErr extends HttpErr { + public formatted = (): unknown => { + return { // follows EKM error response format + "code": this.statusCode, + "message": `message:${this.message}`, + "details": `details:${this.message}` + } + } +} + export const MOCK_KM_LAST_INSERTED_KEY: { [acct: string]: { decryptedPrivateKey: string, publicKey: string } } = {}; // accessed from test runners /** @@ -74,7 +84,7 @@ export const getMockEkmEndpoints = ( // if (acctEmail === 'get.error@key-manager-autogen.flowcrypt.test') { // throw new Error('Intentional error for get.error to test client behavior'); // } - // throw new HttpClientErr(`Unexpectedly calling mockKeyManagerEndpoints:/keys/private GET with acct ${acctEmail}`); + // throw new HttpErr(`Unexpectedly calling mockKeyManagerEndpoints:/keys/private GET with acct ${acctEmail}`); // } // if (isPut(req)) { // const { decryptedPrivateKey, publicKey } = body as Dict; @@ -102,7 +112,7 @@ export const getMockEkmEndpoints = ( // throw new Error('Intentional error for put.error user to test client behavior'); // } // if (acctEmail === 'reject.client.keypair@key-manager-autogen.flowcrypt.test') { - // throw new HttpClientErr(`No key has been generated for ${acctEmail} yet. Please ask your administrator.`, 405); + // throw new HttpErr(`No key has been generated for ${acctEmail} yet. Please ask your administrator.`, 405); // } // if (acctEmail === 'expire@key-manager-keygen-expiration.flowcrypt.test') { // const prv = await KeyUtil.parseMany(decryptedPrivateKey); @@ -124,9 +134,9 @@ export const getMockEkmEndpoints = ( // MOCK_KM_LAST_INSERTED_KEY[acctEmail] = { decryptedPrivateKey, publicKey }; // return {}; // } - // throw new HttpClientErr(`Unexpectedly calling mockKeyManagerEndpoints:/keys/private PUT with acct ${acctEmail}`); + // throw new HttpErr(`Unexpectedly calling mockKeyManagerEndpoints:/keys/private PUT with acct ${acctEmail}`); // } - // throw new HttpClientErr(`Unknown method: ${req.method}`); + // throw new HttpErr(`Unknown method: ${req.method}`); // } // }; } diff --git a/appium/api-mocks/apis/fes/fes-endpoints.ts b/appium/api-mocks/apis/fes/fes-endpoints.ts index 26d9dc7d6..07220c87b 100644 --- a/appium/api-mocks/apis/fes/fes-endpoints.ts +++ b/appium/api-mocks/apis/fes/fes-endpoints.ts @@ -2,10 +2,20 @@ import { IncomingMessage } from 'http'; import { FesConfig, MockConfig } from '../../lib/configuration-types'; -import { HandlersDefinition, HttpClientErr } from '../../lib/api'; +import { HandlersDefinition, HttpErr, Status } from '../../lib/api'; import { MockJwt } from '../../lib/oauth'; import { expectContains, throwIfNotGetMethod } from '../../lib/mock-util'; +export class FesHttpErr extends HttpErr { + public formatted = (): unknown => { + return { // follows FES error response format + "code": this.statusCode, + "message": `message:${this.message}`, + "details": `details:${this.message}` + } + } +} + export const getMockFesEndpoints = ( mockConfig: MockConfig, fesConfig: FesConfig | undefined @@ -17,6 +27,7 @@ export const getMockFesEndpoints = ( return { '/fes/api/': async ({ }, req) => { + throwErrorIfConfigSaysSo(fesConfig); throwIfNotGetMethod(req); return { "vendor": "Mock", @@ -27,17 +38,20 @@ export const getMockFesEndpoints = ( }; }, '/fes/api/v1/client-configuration': async ({ }, req) => { + throwErrorIfConfigSaysSo(fesConfig); throwIfNotGetMethod(req); - return { clientConfiguration: fesConfig.clientConfiguration }; + return { clientConfiguration: fesConfig.clientConfiguration || {} }; }, '/fes/api/v1/message/new-reply-token': async ({ }, req) => { + throwErrorIfConfigSaysSo(fesConfig); if (req.method === 'POST') { authenticate(req); return { 'replyToken': 'mock-fes-reply-token' }; } - throw new HttpClientErr('Not Found', 404); + throw new FesHttpErr('Not Found', Status.NOT_FOUND); }, '/fes/api/v1/message': async ({ body }, req) => { + throwErrorIfConfigSaysSo(fesConfig); // body is a mime-multipart string, we're doing a few smoke checks here without parsing it if (req.method === 'POST') { expectContains(body, '-----BEGIN PGP MESSAGE-----'); @@ -49,10 +63,15 @@ export const getMockFesEndpoints = ( expectContains(body, '"from":"user@disablefesaccesstoken.test:8001"'); return { 'url': `${mockConfig}/message/FES-MOCK-MESSAGE-ID` }; } - throw new HttpClientErr('Not Found', 404); + throw new FesHttpErr('Not Found', Status.NOT_FOUND); }, }; +} +const throwErrorIfConfigSaysSo = (config: FesConfig) => { + if (config.returnError) { + throw new FesHttpErr(config.returnError.message, config.returnError.code); + } } const authenticate = (req: IncomingMessage): string => { diff --git a/appium/api-mocks/apis/google/google-endpoints.ts b/appium/api-mocks/apis/google/google-endpoints.ts index 98e508ad1..3ac5c329d 100644 --- a/appium/api-mocks/apis/google/google-endpoints.ts +++ b/appium/api-mocks/apis/google/google-endpoints.ts @@ -1,9 +1,9 @@ /* ©️ 2016 - present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com */ import { GoogleConfig, MockConfig } from '../../lib/configuration-types'; -import { HandlersDefinition } from '../../lib/api'; -import { GoogleData } from './google-data'; -// import { HttpClientErr, Status } from '../lib/api'; +import { HandlersDefinition, HttpErr } from '../../lib/api'; +// import { GoogleData } from './google-data'; +// import { HttpErr, Status } from '../lib/api'; // import Parse, { ParseMsgResult } from '../../util/parse'; // import { isDelete, isGet, isPost, isPut, parseResourceId } from '../lib/mock-util'; // import { AddressObject, ParsedMail } from 'mailparser'; @@ -13,17 +13,25 @@ import { GoogleData } from './google-data'; // type DraftSaveModel = { message: { raw: string, threadId: string } }; +export class GoogleErr extends HttpErr { + public formatted = (): unknown => { + return { // todo - fix this to resemble google error response format + error: this.message + } + } +} + export const getMockGoogleEndpoints = ( mockConfig: MockConfig, googleConfig: GoogleConfig | undefined ): HandlersDefinition => { - const googleData = new GoogleData('not.implemented@example.test'); + // const googleData = await GoogleData.withInitializedData('not.implemented@example.test'); if (!googleConfig) { return {}; } - googleData.getLabels(); // example to keep TS quiei + // googleData.getLabels(); // example to keep TS quiei // todo return {}; // return { @@ -37,7 +45,7 @@ export const getMockGoogleEndpoints = ( // return oauth.successPage(login_hint, state); // } // } - // throw new HttpClientErr(`Method not implemented for ${req.url}: ${req.method}`); + // throw new HttpErr(`Method not implemented for ${req.url}: ${req.method}`); // }, // '/oauth2/v4/token': async ({ query: { grant_type, refreshToken, client_id, code } }, req) => { // if (isPost(req) && grant_type === 'authorization_code' && code && client_id === oauth.clientId) { // auth code from auth screen gets exchanged for access and refresh tokens @@ -52,11 +60,11 @@ export const getMockGoogleEndpoints = ( // if (isGet(req)) { // return { issued_to: 'issued_to', audience: 'audience', scope: 'scope', expires_in: oauth.expiresIn, access_type: 'offline' }; // } - // throw new HttpClientErr(`Method not implemented for ${req.url}: ${req.method}`); + // throw new HttpErr(`Method not implemented for ${req.url}: ${req.method}`); // }, // '/m8/feeds/contacts/default/thin': async ({ query: { q } }, req) => { // if (!isGet(req)) { - // throw new HttpClientErr(`Method not implemented for ${req.url}: ${req.method}`); + // throw new HttpErr(`Method not implemented for ${req.url}: ${req.method}`); // } // const empty = { feed: { entry: [] } }; // const acct = oauth.checkAuthorizationHeaderWithAccessToken(req.headers.authorization); @@ -144,7 +152,7 @@ export const getMockGoogleEndpoints = ( // } // return { sendAs }; // } - // throw new HttpClientErr(`Method not implemented for ${req.url}: ${req.method}`); + // throw new HttpErr(`Method not implemented for ${req.url}: ${req.method}`); // }, // '/gmail/v1/users/me/messages': async ({ query: { q } }, req) => { // search messages // const acct = oauth.checkAuthorizationHeaderWithAccessToken(req.headers.authorization); @@ -152,7 +160,7 @@ export const getMockGoogleEndpoints = ( // const msgs = (await GoogleData.withInitializedData(acct)).searchMessages(q); // return { messages: msgs.map(({ id, threadId }) => ({ id, threadId })), resultSizeEstimate: msgs.length }; // } - // throw new HttpClientErr(`Method not implemented for ${req.url}: ${req.method}`); + // throw new HttpErr(`Method not implemented for ${req.url}: ${req.method}`); // }, // '/gmail/v1/users/me/messages/?': async ({ query: { format } }, req) => { // get msg or attachment // const acct = oauth.checkAuthorizationHeaderWithAccessToken(req.headers.authorization); @@ -164,22 +172,22 @@ export const getMockGoogleEndpoints = ( // if (attachment) { // return attachment; // } - // throw new HttpClientErr(`MOCK attachment not found for ${acct}: ${id}`, Status.NOT_FOUND); + // throw new HttpErr(`MOCK attachment not found for ${acct}: ${id}`, Status.NOT_FOUND); // } // const msg = data.getMessage(id); // if (msg) { // return GoogleData.fmtMsg(msg, format); // } - // throw new HttpClientErr(`MOCK Message not found for ${acct}: ${id}`, Status.NOT_FOUND); + // throw new HttpErr(`MOCK Message not found for ${acct}: ${id}`, Status.NOT_FOUND); // } - // throw new HttpClientErr(`Method not implemented for ${req.url}: ${req.method}`); + // throw new HttpErr(`Method not implemented for ${req.url}: ${req.method}`); // }, // '/gmail/v1/users/me/labels': async (parsedReq, req) => { // const acct = oauth.checkAuthorizationHeaderWithAccessToken(req.headers.authorization); // if (isGet(req)) { // return { labels: (await GoogleData.withInitializedData(acct)).getLabels() }; // } - // throw new HttpClientErr(`Method not implemented for ${req.url}: ${req.method}`); + // throw new HttpErr(`Method not implemented for ${req.url}: ${req.method}`); // }, // '/gmail/v1/users/me/threads': async ({ }, req) => { // const acct = oauth.checkAuthorizationHeaderWithAccessToken(req.headers.authorization); @@ -187,7 +195,7 @@ export const getMockGoogleEndpoints = ( // const threads = (await GoogleData.withInitializedData(acct)).getThreads(); // return { threads, resultSizeEstimate: threads.length }; // } - // throw new HttpClientErr(`Method not implemented for ${req.url}: ${req.method}`); + // throw new HttpErr(`Method not implemented for ${req.url}: ${req.method}`); // }, // '/gmail/v1/users/me/threads/?': async ({ query: { format } }, req) => { // const acct = oauth.checkAuthorizationHeaderWithAccessToken(req.headers.authorization); @@ -196,7 +204,7 @@ export const getMockGoogleEndpoints = ( // const msgs = (await GoogleData.withInitializedData(acct)).getMessagesByThread(id); // if (!msgs.length) { // const statusCode = id === '16841ce0ce5cb74d' ? 404 : 400; // intentionally testing missing thread - // throw new HttpClientErr(`MOCK thread not found for ${acct}: ${id}`, statusCode); + // throw new HttpErr(`MOCK thread not found for ${acct}: ${id}`, statusCode); // } // return { id, historyId: msgs[0].historyId, messages: msgs.map(m => GoogleData.fmtMsg(m, format)) }; // } @@ -219,7 +227,7 @@ export const getMockGoogleEndpoints = ( // return { id: 'fakesendid', labelIds: ['SENT'], threadId: parseResult.threadId }; // } // } - // throw new HttpClientErr(`Method not implemented for ${req.url}: ${req.method}`); + // throw new HttpErr(`Method not implemented for ${req.url}: ${req.method}`); // }, // '/gmail/v1/users/me/drafts': async (parsedReq, req) => { // if (isPost(req)) { @@ -227,7 +235,7 @@ export const getMockGoogleEndpoints = ( // const body = parsedReq.body as DraftSaveModel; // if (body && body.message && body.message.raw && typeof body.message.raw === 'string') { // if (body.message.threadId && !(await GoogleData.withInitializedData(acct)).getThreads().find(t => t.id === body.message.threadId)) { - // throw new HttpClientErr('The thread you are replying to not found', 404); + // throw new HttpErr('The thread you are replying to not found', 404); // } // const decoded = await Parse.convertBase64ToMimeMsg(body.message.raw); // if (!decoded.text?.startsWith('[flowcrypt:') && !decoded.text?.startsWith('(saving of this draft was interrupted - to decrypt it, send it to yourself)')) { @@ -242,7 +250,7 @@ export const getMockGoogleEndpoints = ( // }; // } // } - // throw new HttpClientErr(`Method not implemented for ${req.url}: ${req.method}`); + // throw new HttpErr(`Method not implemented for ${req.url}: ${req.method}`); // }, // '/gmail/v1/users/me/drafts/?': async (parsedReq, req) => { // const acct = oauth.checkAuthorizationHeaderWithAccessToken(req.headers.authorization); @@ -253,7 +261,7 @@ export const getMockGoogleEndpoints = ( // if (draft) { // return { id: draft.id, message: draft }; // } - // throw new HttpClientErr(`MOCK draft not found for ${acct} (draftId: ${id})`, Status.NOT_FOUND); + // throw new HttpErr(`MOCK draft not found for ${acct} (draftId: ${id})`, Status.NOT_FOUND); // } else if (isPut(req)) { // const raw = (parsedReq.body as any)?.message?.raw as string; // tslint:disable-line: no-unsafe-any // if (!raw) { @@ -272,7 +280,7 @@ export const getMockGoogleEndpoints = ( // } else if (isDelete(req)) { // return {}; // } - // throw new HttpClientErr(`Method not implemented for ${req.url}: ${req.method}`); + // throw new HttpErr(`Method not implemented for ${req.url}: ${req.method}`); // }, // }; } @@ -283,9 +291,9 @@ export const getMockGoogleEndpoints = ( // parsed = await Parse.strictParse(multipartData); // } catch (e) { // if (e instanceof Error) { -// throw new HttpClientErr(e.message, 400); +// throw new HttpErr(e.message, 400); // } -// throw new HttpClientErr('Unknown error', 500); +// throw new HttpErr('Unknown error', 500); // } // return parsed; // }; @@ -295,7 +303,7 @@ export const getMockGoogleEndpoints = ( // if (threadId) { // const messages = (await GoogleData.withInitializedData(acct)).getMessagesByThread(threadId); // if (!messages || !messages.length) { -// throw new HttpClientErr(`Error: The thread you are replying (${threadId}) to not found`, 404); +// throw new HttpErr(`Error: The thread you are replying (${threadId}) to not found`, 404); // } // if (inReplyToMessageId) { // let isMessageExists = false; @@ -309,41 +317,41 @@ export const getMockGoogleEndpoints = ( // } // } // if (!isMessageExists) { -// throw new HttpClientErr(`Error: suplied In-Reply-To header (${inReplyToMessageId}) does not match any messages present in the mock data for thread ${threadId}`, 400); +// throw new HttpErr(`Error: suplied In-Reply-To header (${inReplyToMessageId}) does not match any messages present in the mock data for thread ${threadId}`, 400); // } // } else { -// throw new HttpClientErr(`Error: 'In-Reply-To' must not be empty if there is 'threadId'(${threadId})`, 400); +// throw new HttpErr(`Error: 'In-Reply-To' must not be empty if there is 'threadId'(${threadId})`, 400); // } // } // if (!mimeMsg.subject) { -// throw new HttpClientErr('Error: Subject line is required', 400); +// throw new HttpErr('Error: Subject line is required', 400); // } else { // if (['Re: ', 'Fwd: '].some(e => mimeMsg.subject?.startsWith(e)) && (!threadId || !inReplyToMessageId)) { -// throw new HttpClientErr(`Error: Incorrect subject. Subject can't start from 'Re:' or 'Fwd:'. Current subject is '${mimeMsg.subject}'`, 400); +// throw new HttpErr(`Error: Incorrect subject. Subject can't start from 'Re:' or 'Fwd:'. Current subject is '${mimeMsg.subject}'`, 400); // } else if ((threadId || inReplyToMessageId) && !['Re: ', 'Fwd: '].some(e => mimeMsg.subject?.startsWith(e))) { -// throw new HttpClientErr("Error: Incorrect subject. Subject must start from 'Re:' or 'Fwd:' " + +// throw new HttpErr("Error: Incorrect subject. Subject must start from 'Re:' or 'Fwd:' " + // `if the message has threaId or 'In-Reply-To' header. Current subject is '${mimeMsg.subject}'`, 400); // } // // Special check for 'from alias' test // if (mimeMsg.subject.endsWith('from alias') && mimeMsg.from?.value[0].address !== 'flowcryptcompatibility@gmail.com') { -// throw new HttpClientErr(`Error: Incorrect Email Alias. Should be 'flowcryptcompatibility@gmail.com'. Current '${mimeMsg.from?.value[0].address}'`); +// throw new HttpErr(`Error: Incorrect Email Alias. Should be 'flowcryptcompatibility@gmail.com'. Current '${mimeMsg.from?.value[0].address}'`); // } // } // if (!mimeMsg.text && !mimeMsg.attachments?.length) { -// throw new HttpClientErr('Error: Message body cannot be empty', 400); +// throw new HttpErr('Error: Message body cannot be empty', 400); // } // if ( // !parsedMailAddressObjectAsArray(mimeMsg.to).length && parsedMailAddressObjectAsArray(mimeMsg.to)[0].value.length // || parsedMailAddressObjectAsArray(mimeMsg.to)[0].value.find(em => !allowedRecipients.includes(em.address!)) // ) { -// throw new HttpClientErr('Error: You can\'t send a message to unexisting email address(es)'); +// throw new HttpErr('Error: You can\'t send a message to unexisting email address(es)'); // } // const aliases = [acct]; // if (acct === 'flowcrypt.compatibility@gmail.com') { // aliases.push('flowcryptcompatibility@gmail.com'); // } // if (!mimeMsg.from?.value.length || mimeMsg.from?.value.find(em => !aliases.includes(em.address!))) { -// throw new HttpClientErr('You can\'t send a message from unexisting email address(es)'); +// throw new HttpErr('You can\'t send a message from unexisting email address(es)'); // } // }; diff --git a/appium/api-mocks/apis/google/strategies/send-message-strategy.ts b/appium/api-mocks/apis/google/strategies/send-message-strategy.ts index 22d3fae18..6244ac016 100644 --- a/appium/api-mocks/apis/google/strategies/send-message-strategy.ts +++ b/appium/api-mocks/apis/google/strategies/send-message-strategy.ts @@ -7,7 +7,7 @@ // import { Config } from '../util'; // import { expect } from 'chai'; // import { GoogleData } from '../google-data'; -// import { HttpClientErr } from '../../lib/api'; +// import { HttpErr } from '../../lib/api'; // import { MsgUtil } from '../../../core/crypto/pgp/msg-util'; // import Parse from '../../../util/parse'; // import { parsedMailAddressObjectAsArray } from '../google-endpoints'; @@ -27,13 +27,13 @@ // public test = async (mimeMsg: ParsedMail) => { // const senderEmail = Str.parseEmail(mimeMsg.from!.text).email; // if (!mimeMsg.text?.includes(`${senderEmail} has sent you a password-encrypted email`)) { -// throw new HttpClientErr(`Error checking sent text in:\n\n${mimeMsg.text}`); +// throw new HttpErr(`Error checking sent text in:\n\n${mimeMsg.text}`); // } // if (!mimeMsg.text?.match(/https:\/\/flowcrypt.com\/[a-z0-9A-Z]{10}/)) { -// throw new HttpClientErr(`Error: cannot find pwd encrypted flowcrypt.com/api link in:\n\n${mimeMsg.text}`); +// throw new HttpErr(`Error: cannot find pwd encrypted flowcrypt.com/api link in:\n\n${mimeMsg.text}`); // } // if (!mimeMsg.text?.includes('Follow this link to open it')) { -// throw new HttpClientErr(`Error: cannot find pwd encrypted open link prompt in ${mimeMsg.text}`); +// throw new HttpErr(`Error: cannot find pwd encrypted open link prompt in ${mimeMsg.text}`); // } // } // } @@ -43,16 +43,16 @@ // const senderEmail = Str.parseEmail(mimeMsg.from!.text).email; // const expectedSenderEmail = 'user@standardsubdomainfes.test:8001'; // if (senderEmail !== expectedSenderEmail) { -// throw new HttpClientErr(`Unexpected sender email ${senderEmail}, expecting ${expectedSenderEmail}`); +// throw new HttpErr(`Unexpected sender email ${senderEmail}, expecting ${expectedSenderEmail}`); // } // if (!mimeMsg.text?.includes(`${senderEmail} has sent you a password-encrypted email`)) { -// throw new HttpClientErr(`Error checking sent text in:\n\n${mimeMsg.text}`); +// throw new HttpErr(`Error checking sent text in:\n\n${mimeMsg.text}`); // } // if (!mimeMsg.text?.includes('http://fes.standardsubdomainfes.test:8001/message/FES-MOCK-MESSAGE-ID')) { -// throw new HttpClientErr(`Error: cannot find pwd encrypted FES link in:\n\n${mimeMsg.text}`); +// throw new HttpErr(`Error: cannot find pwd encrypted FES link in:\n\n${mimeMsg.text}`); // } // if (!mimeMsg.text?.includes('Follow this link to open it')) { -// throw new HttpClientErr(`Error: cannot find pwd encrypted open link prompt in ${mimeMsg.text}`); +// throw new HttpErr(`Error: cannot find pwd encrypted open link prompt in ${mimeMsg.text}`); // } // } // } @@ -62,16 +62,16 @@ // const senderEmail = Str.parseEmail(mimeMsg.from!.text).email; // const expectedSenderEmail = 'user@disablefesaccesstoken.test:8001'; // if (senderEmail !== expectedSenderEmail) { -// throw new HttpClientErr(`Unexpected sender email ${senderEmail}, expecting ${expectedSenderEmail}`); +// throw new HttpErr(`Unexpected sender email ${senderEmail}, expecting ${expectedSenderEmail}`); // } // if (!mimeMsg.text?.includes(`${senderEmail} has sent you a password-encrypted email`)) { -// throw new HttpClientErr(`Error checking sent text in:\n\n${mimeMsg.text}`); +// throw new HttpErr(`Error checking sent text in:\n\n${mimeMsg.text}`); // } // if (!mimeMsg.text?.includes('http://fes.disablefesaccesstoken.test:8001/message/FES-MOCK-MESSAGE-ID')) { -// throw new HttpClientErr(`Error: cannot find pwd encrypted FES link in:\n\n${mimeMsg.text}`); +// throw new HttpErr(`Error: cannot find pwd encrypted FES link in:\n\n${mimeMsg.text}`); // } // if (!mimeMsg.text?.includes('Follow this link to open it')) { -// throw new HttpClientErr(`Error: cannot find pwd encrypted open link prompt in ${mimeMsg.text}`); +// throw new HttpErr(`Error: cannot find pwd encrypted open link prompt in ${mimeMsg.text}`); // } // } // } @@ -83,11 +83,11 @@ // const keyInfo = await Config.getKeyInfo(["flowcrypt.compatibility.1pp1", "flowcrypt.compatibility.2pp1"]); // const decrypted = await MsgUtil.decryptMessage({ kisWithPp: keyInfo!, encryptedData: Buf.fromUtfStr(mimeMsg.text || '') }); // if (!decrypted.success) { -// throw new HttpClientErr(`Error: can't decrypt message`); +// throw new HttpErr(`Error: can't decrypt message`); // } // const textContent = decrypted.content.toUtfStr(); // if (!textContent.includes(this.footer)) { -// throw new HttpClientErr(`Error: Msg Text doesn't contain footer. Current: '${mimeMsg.text}', expected footer: '${this.footer}'`); +// throw new HttpErr(`Error: Msg Text doesn't contain footer. Current: '${mimeMsg.text}', expected footer: '${this.footer}'`); // } // } // } @@ -100,17 +100,17 @@ // const keyInfo = await Config.getKeyInfo(["flowcrypt.compatibility.1pp1", "flowcrypt.compatibility.2pp1"]); // const decrypted = await MsgUtil.decryptMessage({ kisWithPp: keyInfo!, encryptedData: Buf.fromUtfStr(mimeMsg.text!) }); // if (!decrypted.success) { -// throw new HttpClientErr(`Error: Could not successfully verify signed message`); +// throw new HttpErr(`Error: Could not successfully verify signed message`); // } // if (!decrypted.signature) { -// throw new HttpClientErr(`Error: The message isn't signed.`); +// throw new HttpErr(`Error: The message isn't signed.`); // } // if (decrypted.signature.signer?.longid !== this.signedBy) { -// throw new HttpClientErr(`Error: expected message signed by ${this.signedBy} but was actually signed by ${decrypted.signature.signer?.longid}`); +// throw new HttpErr(`Error: expected message signed by ${this.signedBy} but was actually signed by ${decrypted.signature.signer?.longid}`); // } // const content = decrypted.content.toUtfStr(); // if (!content.includes(this.expectedText)) { -// throw new HttpClientErr(`Error: Contents don't match. Expected: '${this.expectedText}' but got: '${content}'.`); +// throw new HttpErr(`Error: Contents don't match. Expected: '${this.expectedText}' but got: '${content}'.`); // } // } // } @@ -120,7 +120,7 @@ // public test = async (mimeMsg: ParsedMail) => { // if (!mimeMsg.text?.includes(this.expectedText)) { -// throw new HttpClientErr(`Error: Msg Text is not matching expected. Current: '${mimeMsg.text}', expected: '${this.expectedText}'`); +// throw new HttpErr(`Error: Msg Text is not matching expected. Current: '${mimeMsg.text}', expected: '${this.expectedText}'`); // } // } // } @@ -143,11 +143,11 @@ // const keyInfo = await Config.getKeyInfo(["flowcrypt.compatibility.1pp1", "flowcrypt.compatibility.2pp1"]); // const decrypted = await MsgUtil.decryptMessage({ kisWithPp: keyInfo!, encryptedData: Buf.fromUtfStr(mimeMsg.text!) }); // if (!decrypted.success) { -// throw new HttpClientErr(`Error: can't decrypt message`); +// throw new HttpErr(`Error: can't decrypt message`); // } // const textContent = decrypted.content.toUtfStr(); // if (!textContent.endsWith(this.quotedContent)) { -// throw new HttpClientErr(`Error: Quoted content isn't included to the Msg. Msg text: '${textContent}'\n Quoted part: '${this.quotedContent}'`, 400); +// throw new HttpErr(`Error: Quoted content isn't included to the Msg. Msg text: '${textContent}'\n Quoted part: '${this.quotedContent}'`, 400); // } // } // } @@ -156,13 +156,13 @@ // public test = async (mimeMsg: ParsedMail) => { // const hasAtLeastOneRecipient = (ao: AddressObject[]) => ao && ao.length && ao[0].value && ao[0].value.length && ao[0].value[0].address; // if (!hasAtLeastOneRecipient(parsedMailAddressObjectAsArray(mimeMsg.to))) { -// throw new HttpClientErr(`Error: There is no 'To' header.`, 400); +// throw new HttpErr(`Error: There is no 'To' header.`, 400); // } // if (!hasAtLeastOneRecipient(parsedMailAddressObjectAsArray(mimeMsg.cc))) { -// throw new HttpClientErr(`Error: There is no 'Cc' header.`, 400); +// throw new HttpErr(`Error: There is no 'Cc' header.`, 400); // } // if (!hasAtLeastOneRecipient(parsedMailAddressObjectAsArray(mimeMsg.bcc))) { -// throw new HttpClientErr(`Error: There is no 'Bcc' header.`, 400); +// throw new HttpErr(`Error: There is no 'Bcc' header.`, 400); // } // } // } diff --git a/appium/api-mocks/apis/wkd/wkd-endpoints.ts b/appium/api-mocks/apis/wkd/wkd-endpoints.ts index 4ac57f193..bc3d78890 100644 --- a/appium/api-mocks/apis/wkd/wkd-endpoints.ts +++ b/appium/api-mocks/apis/wkd/wkd-endpoints.ts @@ -1,6 +1,6 @@ /* ©️ 2016 - present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com */ -import { HandlersDefinition } from '../../lib/api'; +import { HandlersDefinition, HttpErr } from '../../lib/api'; import { MockConfig, WkdConfig } from '../../lib/configuration-types'; // import { KeyUtil } from '../../core/crypto/key'; @@ -8,6 +8,16 @@ import { MockConfig, WkdConfig } from '../../lib/configuration-types'; // import { testConstants } from '../../tests/tooling/consts'; // import { HandlersDefinition } from '../all-apis-mock'; +export class WkdHttpErr extends HttpErr { + public formatted = (): unknown => { + return { // follows WKD error response format + "code": this.statusCode, + "message": `message:${this.message}`, + "details": `details:${this.message}` + } + } +} + /** * Web Key Directory - distributes private keys to users who own them */ diff --git a/appium/api-mocks/lib/api.ts b/appium/api-mocks/lib/api.ts index 95f7e12e6..95ff20672 100644 --- a/appium/api-mocks/lib/api.ts +++ b/appium/api-mocks/lib/api.ts @@ -5,13 +5,6 @@ import * as http from 'http'; import { readFileSync } from 'fs'; // tslint:disable:await-returned-promise -export class HttpAuthErr extends Error { } -export class HttpClientErr extends Error { - constructor(message: string, public statusCode = 400) { - super(message); - } -} - export type HandlersDefinition = Handlers<{ query: { [k: string]: string; }; body?: unknown; }, unknown>; export enum Status { @@ -65,11 +58,7 @@ export class Api { process.exit(1); } }).catch((e) => { - if (e instanceof HttpAuthErr) { - response.statusCode = Status.UNAUTHORIZED; - response.setHeader('WWW-Authenticate', `Basic realm="${this.apiName}"`); - e.stack = undefined; - } else if (e instanceof HttpClientErr) { + if (e instanceof HttpErr) { response.statusCode = e.statusCode; e.stack = undefined; } else { @@ -150,7 +139,7 @@ export class Api { res.setHeader('content-type', 'application/json'); return this.fmtRes({ alive: true }); } - throw new HttpClientErr(`unknown MOCK path ${req.url}`); + throw new HttpErr(`unknown MOCK path ${req.url}`, Status.BAD_REQUEST); } protected chooseHandler = (req: http.IncomingMessage): RequestHandler | undefined => { @@ -178,7 +167,16 @@ export class Api { if (String(e).includes('invalid_grant')) { return Buffer.from(JSON.stringify({ "error": "invalid_grant", "error_description": "Bad Request" })); } - return Buffer.from(JSON.stringify({ "error": { "message": e instanceof Error ? e.message : String(e), stack: e instanceof Error ? e.stack : '' } })); + if (!(e instanceof HttpErr)) { + if (e instanceof Error) { + const newErr = new HttpErr(e.message, Status.SERVER_ERROR) + newErr.stack = e.stack; + e = newErr; + } else { + e = new HttpErr("Non-error thrown in mock: " + String(e), Status.SERVER_ERROR); + } + } + return Buffer.from(JSON.stringify((e as HttpErr).formatted())); } protected fmtHandlerRes = (handlerRes: RES, serverRes: http.ServerResponse): Buffer => { @@ -212,7 +210,7 @@ export class Api { req.on('data', (chunk: Buffer) => { byteLength += chunk.length; if (this.maxRequestSizeBytes && byteLength > this.maxRequestSizeBytes) { - reject(new HttpClientErr(`Message over ${this.maxRequestSizeMb} MB`)); + reject(new HttpErr(`Message over ${this.maxRequestSizeMb} MB`, Status.BAD_REQUEST)); } else { body.push(chunk); } @@ -282,3 +280,17 @@ export class Api { } } + +export class HttpErr extends Error { + constructor(message: string, public statusCode: number) { + super(message); + } + public formatted = (): unknown => { + return { + "mockError": this.message, + "mockStack": this.stack || "no stack", + "noFormatter": "if you wanted a different error format, subclass from HttpErr and add a formatter", + } + } +} + diff --git a/appium/api-mocks/lib/configuration-types.ts b/appium/api-mocks/lib/configuration-types.ts index 92e2d81cd..6fbf6ecbd 100644 --- a/appium/api-mocks/lib/configuration-types.ts +++ b/appium/api-mocks/lib/configuration-types.ts @@ -20,8 +20,20 @@ type Fes$ClientConfiguration = { enforce_keygen_expire_months?: number, }; -export type FesConfig = { clientConfiguration: Fes$ClientConfiguration }; -export type AttesterConfig = { enableSubmittingPubkeys?: boolean, servedPubkeys?: Dict }; -export type GoogleConfig = { allowedRecipients: [string] }; +export type FesConfig = { + returnError?: { code: number, message: string }, + clientConfiguration?: Fes$ClientConfiguration +}; + +export type AttesterConfig = { + enableSubmittingPubkeys?: boolean, + servedPubkeys?: Dict +}; + +export type GoogleConfig = { + allowedRecipients: [string] +}; + export type WkdConfig = {}; + export type EkmConfig = {}; \ No newline at end of file diff --git a/appium/api-mocks/lib/mock-util.ts b/appium/api-mocks/lib/mock-util.ts index 20606c16d..e161e5d5e 100644 --- a/appium/api-mocks/lib/mock-util.ts +++ b/appium/api-mocks/lib/mock-util.ts @@ -1,7 +1,7 @@ /* ©️ 2016 - present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com */ import { IncomingMessage } from 'http'; -import { HttpClientErr } from './api'; +import { HttpErr, Status } from './api'; import * as request from 'request'; export const isGet = (r: IncomingMessage) => r.method === 'GET' || r.method === 'HEAD'; @@ -18,7 +18,7 @@ export const expectContains = (haystack: unknown, needle: string) => { export const throwIfNotGetMethod = (req: IncomingMessage) => { if (req.method !== 'GET') { - throw new HttpClientErr('Unsupported method'); + throw new HttpErr('Unsupported method', Status.BAD_REQUEST); } } diff --git a/appium/api-mocks/lib/oauth.ts b/appium/api-mocks/lib/oauth.ts index a490ed656..45d878bb1 100644 --- a/appium/api-mocks/lib/oauth.ts +++ b/appium/api-mocks/lib/oauth.ts @@ -1,6 +1,6 @@ /* ©️ 2016 - present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com */ -import { HttpClientErr, Status } from './api'; +import { HttpErr, Status } from './api'; import { Buf } from '../core/buf'; import { Str } from '../core/common'; @@ -51,18 +51,18 @@ export class OauthMock { const id_token = this.generateIdToken(acct); return { access_token, expires_in: this.expiresIn, id_token, token_type: 'Bearer' }; } catch (e) { - throw new HttpClientErr('invalid_grant', Status.BAD_REQUEST); + throw new HttpErr('invalid_grant', Status.BAD_REQUEST); } } public checkAuthorizationHeaderWithAccessToken = (authorization: string | undefined) => { if (!authorization) { - throw new HttpClientErr('Missing mock bearer authorization header', Status.UNAUTHORIZED); + throw new HttpErr('Missing mock bearer authorization header', Status.UNAUTHORIZED); } const accessToken = authorization.replace(/^Bearer /, ''); const acct = this.acctByAccessToken[accessToken]; if (!acct) { - throw new HttpClientErr('Invalid mock auth token', Status.UNAUTHORIZED); + throw new HttpErr('Invalid mock auth token', Status.UNAUTHORIZED); } return acct; } @@ -72,12 +72,12 @@ export class OauthMock { */ public checkAuthorizationHeaderWithIdToken = (authorization: string | undefined) => { if (!authorization) { - throw new HttpClientErr('Missing mock bearer authorization header', Status.UNAUTHORIZED); + throw new HttpErr('Missing mock bearer authorization header', Status.UNAUTHORIZED); } const accessToken = authorization.replace(/^Bearer /, ''); const acct = this.acctByIdToken[accessToken]; if (!acct) { - throw new HttpClientErr('Invalid idToken token', Status.UNAUTHORIZED); + throw new HttpErr('Invalid idToken token', Status.UNAUTHORIZED); } return acct; } @@ -104,7 +104,7 @@ export class OauthMock { if (this.accessTokenByRefreshToken[refreshToken]) { return this.accessTokenByRefreshToken[refreshToken]; } - throw new HttpClientErr('Wrong mock refresh token', Status.UNAUTHORIZED); + throw new HttpErr('Wrong mock refresh token', Status.UNAUTHORIZED); } private htmlPage = (title: string, content: string) => { diff --git a/appium/api-mocks/mock.ts b/appium/api-mocks/mock.ts index da2873e89..64167713c 100644 --- a/appium/api-mocks/mock.ts +++ b/appium/api-mocks/mock.ts @@ -58,7 +58,7 @@ export class MockApi { () => getMockGoogleEndpoints(this.mockConfig, this.googleConfig), () => getMockEkmEndpoints(this.mockConfig, this.ekmConfig), () => getMockWkdEndpoints(this.mockConfig, this.wkdConfig), - ]); + ], undefined, false); await api.listen(this.port); try { await testRunner(); diff --git a/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts b/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts index 4a7acfa12..3d78c2940 100644 --- a/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts +++ b/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts @@ -12,10 +12,22 @@ describe('LOGIN: ', () => { mockApi.fesConfig = { clientConfiguration: { key_manager_url: 'INTENTIONAL BAD URL' } }; await mockApi.withMockedApis(async () => { await SplashScreen.login(); - await browser.pause(30000); - // todo - currently this passes because we are not testing the desired result yet - // it logs in and shows a "network lost" but should be showing a more specific modal - // mock is not reached yet probably due to app security settings (plain http) + // todo - replace the following pause with wait for modal error + // that says "Please check if key manager url set correctly" + await browser.pause(5000); }); }); + + it('setup shows meaningful error when FES returns 400', async () => { + const mockApi = new MockApi(); + mockApi.fesConfig = { returnError: { code: 400, message: "some client err" } }; + await mockApi.withMockedApis(async () => { + await SplashScreen.login(); + // todo - replace the following pause with wait for modal error + await browser.pause(5000); + }); + }); + + // todo - app shows meaningful error when FES returns wrong err format + }); From 45bad58aea6f8d299d6ddf123ce140b0956db2ae Mon Sep 17 00:00:00 2001 From: tomholub Date: Sat, 4 Dec 2021 11:14:54 +0100 Subject: [PATCH 06/10] split spec into two --- ...onsistentClientConfiguration.spec copy.ts} | 3 +-- .../SetupShowsMeaningfulErrorFromFES.spec.ts | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) rename appium/tests/specs/mock/setup/{SetupFailsWithInconsistentClientConfiguration.spec.ts => SetupFailsWithInconsistentClientConfiguration.spec copy.ts} (95%) create mode 100644 appium/tests/specs/mock/setup/SetupShowsMeaningfulErrorFromFES.spec.ts diff --git a/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts b/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec copy.ts similarity index 95% rename from appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts rename to appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec copy.ts index 3d78c2940..d6c56bbd8 100644 --- a/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts +++ b/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec copy.ts @@ -1,11 +1,10 @@ import { MockApi } from 'api-mocks/mock'; import { SplashScreen, - // SetupKeyScreen, } from '../../../screenobjects/all-screens'; -describe('LOGIN: ', () => { +describe('SETUP: ', () => { it('app setup fails with bad EKM URL', async () => { const mockApi = new MockApi(); diff --git a/appium/tests/specs/mock/setup/SetupShowsMeaningfulErrorFromFES.spec.ts b/appium/tests/specs/mock/setup/SetupShowsMeaningfulErrorFromFES.spec.ts new file mode 100644 index 000000000..daff6c0ed --- /dev/null +++ b/appium/tests/specs/mock/setup/SetupShowsMeaningfulErrorFromFES.spec.ts @@ -0,0 +1,19 @@ +import { MockApi } from 'api-mocks/mock'; +import { + SplashScreen, +} from '../../../screenobjects/all-screens'; + + +describe('SETUP: ', () => { + + it('setup shows meaningful error when FES returns 400', async () => { + const mockApi = new MockApi(); + mockApi.fesConfig = { returnError: { code: 400, message: "some client err" } }; + await mockApi.withMockedApis(async () => { + await SplashScreen.login(); + // todo - replace the following pause with wait for modal error + await browser.pause(5000); + }); + }); + +}); From 325da5032215faf04cc42f9bb55d20d1ed3d29ce Mon Sep 17 00:00:00 2001 From: tomholub Date: Sat, 4 Dec 2021 11:15:48 +0100 Subject: [PATCH 07/10] remove dup test --- ...sWithInconsistentClientConfiguration.spec copy.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec copy.ts b/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec copy.ts index d6c56bbd8..516e2f06f 100644 --- a/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec copy.ts +++ b/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec copy.ts @@ -17,16 +17,4 @@ describe('SETUP: ', () => { }); }); - it('setup shows meaningful error when FES returns 400', async () => { - const mockApi = new MockApi(); - mockApi.fesConfig = { returnError: { code: 400, message: "some client err" } }; - await mockApi.withMockedApis(async () => { - await SplashScreen.login(); - // todo - replace the following pause with wait for modal error - await browser.pause(5000); - }); - }); - - // todo - app shows meaningful error when FES returns wrong err format - }); From ce4556b1ce463957b2dcd1de78df12711b3a8f72 Mon Sep 17 00:00:00 2001 From: tomholub Date: Sat, 4 Dec 2021 11:16:22 +0100 Subject: [PATCH 08/10] rename --- ...y.ts => SetupFailsWithInconsistentClientConfiguration.spec.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename appium/tests/specs/mock/setup/{SetupFailsWithInconsistentClientConfiguration.spec copy.ts => SetupFailsWithInconsistentClientConfiguration.spec.ts} (100%) diff --git a/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec copy.ts b/appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts similarity index 100% rename from appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec copy.ts rename to appium/tests/specs/mock/setup/SetupFailsWithInconsistentClientConfiguration.spec.ts From a031eb5bd5386e22f4c6eb41261cb0a36962101d Mon Sep 17 00:00:00 2001 From: tomholub Date: Sat, 4 Dec 2021 11:17:42 +0100 Subject: [PATCH 09/10] removed login test --- appium/config/wdio.live.conf.js | 3 --- .../tests/specs/live/login/GmailLogin.spec.ts | 22 ------------------- 2 files changed, 25 deletions(-) delete mode 100644 appium/tests/specs/live/login/GmailLogin.spec.ts diff --git a/appium/config/wdio.live.conf.js b/appium/config/wdio.live.conf.js index 322715687..c3fbd3d2a 100644 --- a/appium/config/wdio.live.conf.js +++ b/appium/config/wdio.live.conf.js @@ -7,9 +7,6 @@ config.suites = { all: [ './tests/specs/live/**/*.spec.ts' ], - smoke: [ - './tests/specs/live/login/GmailLogin.spec.ts' - ], settings: [ './tests/specs/live/settings/*.spec.ts' ], diff --git a/appium/tests/specs/live/login/GmailLogin.spec.ts b/appium/tests/specs/live/login/GmailLogin.spec.ts deleted file mode 100644 index 8304517bd..000000000 --- a/appium/tests/specs/live/login/GmailLogin.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { - SplashScreen, - SetupKeyScreen, - MenuBarScreen, - MailFolderScreen -} from '../../../screenobjects/all-screens'; - - -describe('LOGIN: ', () => { - - it('user is able to login via gmail', async () => { - await SplashScreen.login(); - await SetupKeyScreen.setPassPhrase(); - await MailFolderScreen.checkInboxScreen(); - - await MenuBarScreen.clickMenuIcon(); - await MenuBarScreen.checkUserEmail(); - - await MenuBarScreen.clickLogout(); - await SplashScreen.checkLoginPage(); - }); -}); From f911dd8e3afd67957cd710e5db2c2f928e488d9e Mon Sep 17 00:00:00 2001 From: tomholub Date: Sat, 4 Dec 2021 12:25:56 +0100 Subject: [PATCH 10/10] fix specs --- .../specs/live/inbox/CheckAllEmailSignatureCases.spec.ts | 2 +- .../live/inbox/CheckEncryptedEmailAfterRestartApp.spec.ts | 4 ++-- .../specs/live/inbox/CheckMessageProcessingErrors.spec.ts | 4 ++-- .../live/inbox/CheckReplyAndForwardForEncryptedEmail.spec.ts | 4 ++-- appium/tests/specs/live/inbox/ReadAttachmentEmail.spec.ts | 4 ++-- .../tests/specs/live/inbox/ReadEmailAfterRestartApp.spec.ts | 4 ++-- appium/tests/specs/live/inbox/ReadKeyMismatchEmail.spec.ts | 4 ++-- appium/tests/specs/live/inbox/ReadTextEmail.spec.ts | 4 ++-- .../specs/live/settings/CheckSettingsForLoggedUser.spec.ts | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/appium/tests/specs/live/inbox/CheckAllEmailSignatureCases.spec.ts b/appium/tests/specs/live/inbox/CheckAllEmailSignatureCases.spec.ts index 77699be74..33787d864 100644 --- a/appium/tests/specs/live/inbox/CheckAllEmailSignatureCases.spec.ts +++ b/appium/tests/specs/live/inbox/CheckAllEmailSignatureCases.spec.ts @@ -4,7 +4,7 @@ import { MailFolderScreen, EmailScreen, SearchScreen -} from '../../screenobjects/all-screens'; +} from '../../../screenobjects/all-screens'; describe('INBOX: ', () => { diff --git a/appium/tests/specs/live/inbox/CheckEncryptedEmailAfterRestartApp.spec.ts b/appium/tests/specs/live/inbox/CheckEncryptedEmailAfterRestartApp.spec.ts index d24ef829c..955a0e753 100644 --- a/appium/tests/specs/live/inbox/CheckEncryptedEmailAfterRestartApp.spec.ts +++ b/appium/tests/specs/live/inbox/CheckEncryptedEmailAfterRestartApp.spec.ts @@ -3,9 +3,9 @@ import { SetupKeyScreen, MailFolderScreen, EmailScreen -} from '../../screenobjects/all-screens'; +} from '../../../screenobjects/all-screens'; -import { CommonData } from '../../data'; +import { CommonData } from '../../../data'; describe('INBOX: ', () => { diff --git a/appium/tests/specs/live/inbox/CheckMessageProcessingErrors.spec.ts b/appium/tests/specs/live/inbox/CheckMessageProcessingErrors.spec.ts index b569bfc36..7c3eb6f61 100644 --- a/appium/tests/specs/live/inbox/CheckMessageProcessingErrors.spec.ts +++ b/appium/tests/specs/live/inbox/CheckMessageProcessingErrors.spec.ts @@ -4,9 +4,9 @@ import { MailFolderScreen, EmailScreen, SearchScreen -} from '../../screenobjects/all-screens'; +} from '../../../screenobjects/all-screens'; -import { CommonData } from '../../data'; +import { CommonData } from '../../../data'; describe('INBOX: ', () => { diff --git a/appium/tests/specs/live/inbox/CheckReplyAndForwardForEncryptedEmail.spec.ts b/appium/tests/specs/live/inbox/CheckReplyAndForwardForEncryptedEmail.spec.ts index ecc188d92..8d3bd410d 100644 --- a/appium/tests/specs/live/inbox/CheckReplyAndForwardForEncryptedEmail.spec.ts +++ b/appium/tests/specs/live/inbox/CheckReplyAndForwardForEncryptedEmail.spec.ts @@ -4,9 +4,9 @@ import { MailFolderScreen, EmailScreen, NewMessageScreen -} from '../../screenobjects/all-screens'; +} from '../../../screenobjects/all-screens'; -import { CommonData } from '../../data'; +import { CommonData } from '../../../data'; describe('INBOX: ', () => { diff --git a/appium/tests/specs/live/inbox/ReadAttachmentEmail.spec.ts b/appium/tests/specs/live/inbox/ReadAttachmentEmail.spec.ts index b2e18c721..02b01a2a8 100644 --- a/appium/tests/specs/live/inbox/ReadAttachmentEmail.spec.ts +++ b/appium/tests/specs/live/inbox/ReadAttachmentEmail.spec.ts @@ -4,9 +4,9 @@ import { MailFolderScreen, EmailScreen, AttachmentScreen -} from '../../screenobjects/all-screens'; +} from '../../../screenobjects/all-screens'; -import { CommonData } from '../../data'; +import { CommonData } from '../../../data'; describe('INBOX: ', () => { diff --git a/appium/tests/specs/live/inbox/ReadEmailAfterRestartApp.spec.ts b/appium/tests/specs/live/inbox/ReadEmailAfterRestartApp.spec.ts index 01dfe103e..6182b795e 100644 --- a/appium/tests/specs/live/inbox/ReadEmailAfterRestartApp.spec.ts +++ b/appium/tests/specs/live/inbox/ReadEmailAfterRestartApp.spec.ts @@ -3,9 +3,9 @@ import { SetupKeyScreen, MailFolderScreen, EmailScreen -} from '../../screenobjects/all-screens'; +} from '../../../screenobjects/all-screens'; -import { CommonData } from '../../data'; +import { CommonData } from '../../../data'; describe('INBOX: ', () => { diff --git a/appium/tests/specs/live/inbox/ReadKeyMismatchEmail.spec.ts b/appium/tests/specs/live/inbox/ReadKeyMismatchEmail.spec.ts index 366d9f7d4..ff36d5350 100644 --- a/appium/tests/specs/live/inbox/ReadKeyMismatchEmail.spec.ts +++ b/appium/tests/specs/live/inbox/ReadKeyMismatchEmail.spec.ts @@ -3,9 +3,9 @@ import { SetupKeyScreen, MailFolderScreen, EmailScreen -} from '../../screenobjects/all-screens'; +} from '../../../screenobjects/all-screens'; -import { CommonData } from '../../data'; +import { CommonData } from '../../../data'; describe('INBOX: ', () => { diff --git a/appium/tests/specs/live/inbox/ReadTextEmail.spec.ts b/appium/tests/specs/live/inbox/ReadTextEmail.spec.ts index 1e78570e4..0b447419a 100644 --- a/appium/tests/specs/live/inbox/ReadTextEmail.spec.ts +++ b/appium/tests/specs/live/inbox/ReadTextEmail.spec.ts @@ -3,9 +3,9 @@ import { SetupKeyScreen, MailFolderScreen, EmailScreen -} from '../../screenobjects/all-screens'; +} from '../../../screenobjects/all-screens'; -import { CommonData } from '../../data'; +import { CommonData } from '../../../data'; describe('INBOX: ', () => { diff --git a/appium/tests/specs/live/settings/CheckSettingsForLoggedUser.spec.ts b/appium/tests/specs/live/settings/CheckSettingsForLoggedUser.spec.ts index cf801c100..dc98ea2ee 100644 --- a/appium/tests/specs/live/settings/CheckSettingsForLoggedUser.spec.ts +++ b/appium/tests/specs/live/settings/CheckSettingsForLoggedUser.spec.ts @@ -6,7 +6,7 @@ import { KeysScreen, PublicKeyScreen, MailFolderScreen -} from '../../screenobjects/all-screens'; +} from '../../../screenobjects/all-screens'; describe('SETTINGS: ', () => {